Friday, September 21, 2012

Web Server Basics | Java Sockets | Android Sockets

I recently came across this idea of creating a web server. And surprisingly it is not as bad as it seems to be. I chose java for implementing it cause it was the easiest. A web server is a software that runs on your computer (the server), and it acts as a server that sends web pages from your computer to another when asked for. The most simplest way of knowing this is to build one. Lets quickly build a server that outputs date on your browser for an instance.



  1. import java.net.*;
  2. import java.io.*;

  3. public class Server {
  4. public static void main(String[] args)
  5. {
  6. try
  7. {
  8. //Create a socket at port 80. The port over which browser usually connects
  9. ServerSocket sock = new ServerSocket(80);
  10. //Go into a loop and wait for connections to occur
  11. while(true)
  12. {
  13. //Accept a connection
  14. Socket client = sock.accept();
  15. //set PrintWriter to the output stream of the connected client
  16. PrintWriter pout = new PrintWriter(client.getOutputStream(), true);
  17. //Print date from java.util to the client's output stream
  18. pout.println(new java.util.Date().toString());
  19. //Close the connection with the client
  20. client.close();
  21. }
  22. }
  23. catch (Exception ioe)
  24. {
  25. //In case of exceptions print it to the console.
  26. System.out.println(ioe);
  27. }
  28. }

  29. }
This is a very simple program that does nothing but print date on the screen of the browser. Compile it

javac Server.java                                                                                 (Both Windows and Linux)

And run it 

java Server                                                                                            (Both Windows and Linux)

Now open your browser and type in http://localhost/ or http://127.0.0.1/ and if everything has gone fine then voila.



Now that it is simple to create it in Java, why not android. Open up eclipse and set this layout



  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent" >

  5.     <Button
  6.         android:id="@+id/button1"
  7.         android:layout_width="wrap_content"
  8.         android:layout_height="wrap_content"
  9.         android:layout_alignParentBottom="true"
  10.         android:layout_centerHorizontal="true"
  11.         android:text="@string/runserver" />

  12.     <TextView
  13.         android:id="@+id/textView1"
  14.         android:layout_width="wrap_content"
  15.         android:layout_height="wrap_content"
  16.         android:layout_above="@+id/button1"
  17.         android:layout_alignParentLeft="true"
  18.         android:layout_alignParentRight="true"
  19.         android:layout_alignParentTop="true"/>
  20.   
  21. </RelativeLayout>





And Update strings.xml to add the "Run Server" to strings.xml, this is not necessary but a good android programming practice to include all the strings in the xml files and nothing in the program itself.


  1. <resources>

  2.     <string name="app_name">WebServer</string>
  3.     <string name="menu_settings">Settings</string>
  4.     <string name="runserver">Run Server</string><string name="title_activity_main">WebServer</string>
  5.     

  6. </resources>

And update the manifest to include android:permission:INTERNET



  1. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  2.     package="com.regnartstranger.webserver"
  3.     android:versionCode="1"
  4.     android:versionName="1.0" >

  5.     <uses-sdk
  6.         android:minSdkVersion="10"
  7.         android:targetSdkVersion="15" />
  8.     <uses-permission android:name="android.permission.INTERNET" />
  9.     
  10.     
  11.     <application
  12.         android:icon="@drawable/ic_launcher"
  13.         android:label="@string/app_name"
  14.         android:theme="@style/AppTheme" >
  15.         <activity
  16.             android:name=".WebServer"
  17.             android:label="@string/title_activity_main" >
  18.             <intent-filter>
  19.                 <action android:name="android.intent.action.MAIN" />

  20.                 <category android:name="android.intent.category.LAUNCHER" />
  21.             </intent-filter>
  22.         </activity>
  23.     </application>

  24. </manifest>


In the main WebServer.java file use this code

  1. package com.regnartstranger.webserver;

  2. import android.os.Bundle;
  3. import android.app.Activity;
  4. import android.view.Menu;
  5. import android.view.View;
  6. import android.widget.Button;
  7. import android.widget.TextView;

  8. import java.net.*;
  9. import java.io.*;

  10. public class WebServer extends Activity {

  11. @Override
  12.     public void onCreate(Bundle savedInstanceState) {
  13.         super.onCreate(savedInstanceState);
  14.         setContentView(R.layout.activity_main);
  15.         Button runserver = (Button)findViewById(R.id.button1);
  16.         runserver.setOnClickListener((android.view.View.OnClickListener) new Server());
  17.        }
  18.     public class Server implements android.view.View.OnClickListener {
  19.    
  20.     public void onClick(View clickedButton) {
  21.     TextView textMsg = (TextView)findViewById(R.id.textView1);
  22.     try{
  23.     while(true){
  24.     ServerSocket socket = new ServerSocket(1234);
  25.                 Socket client = socket.accept();
  26.         PrintWriter pout = new PrintWriter(client.getOutputStream(), true);
  27.         pout.println("Android Webserver");
  28.            client.close();
  29.            socket.close();
  30.     }
  31.     }
  32.     catch(Exception ioe)
  33.                 {
  34.                 System.err.print(ioe);
  35.         textMsg.append("Error: " + ioe.getMessage() + "\n" + "Desc: " + ioe.getLocalizedMessage() + "\n");
  36.                 }
  37.     }
  38.     }
  39.    

  40.     @Override
  41.     public boolean onCreateOptionsMenu(Menu menu) {
  42.         getMenuInflater().inflate(R.menu.activity_main, menu);
  43.         return true;
  44.     }
  45. }

Now compile and load the program into your phone. Connect your computer to the phone's internet connection. And open the browser. Now to find out which ip the phone is broadcasting open up abd shell and type netcfg. This should display up the broadcast address of the server.



As you can clearly see my computer connected to the usb internet of my phone is broadcasting at http://192.168.42.129

Similarly find out yours and then open up browser and type in the ip followed by the port 1234. In my case it is http://192.168.42.129:1234/ and we get this


The program may report that the activity encountered unexpected error. Giving you the option to either "Force close" or "Wait". This happens because the activity is struck int the while(true) loop and is not responding to create changes in activity. Select "wait" until you want the server running. The solution to avoid this is to create a background process that runs asynchronously, and finishes the job. Try doing this google Async task android.

But http isn't this simple. It is standardized to have some protocols in it that has to be adhered to. Firstly Browser must send some message so that the server will know what it wants. Let us adjust the last program to get this message.

  1. import java.net.*;
  2. import java.io.*;

  3. public class Server {
  4. public static void main(String[] args)
  5. {
  6. try
  7. {
  8. //Create a socket at port 80. The port over which browser usually connects
  9. ServerSocket sock = new ServerSocket(80);
  10. //Go into a loop and wait for connections to occur
  11. while(true)
  12. {
  13. //Accept a connection
  14. Socket client = sock.accept();
  15. //Create a buffer to read the client request
  16. BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));
  17. //Print out the requested line
  18. System.out.println(input.readLine());
  19. //set PrintWriter to the output stream of the connected client
  20. PrintWriter pout = new PrintWriter(client.getOutputStream(), true);
  21. //Print date from java.util to the client's output stream
  22. pout.println(new java.util.Date().toString());
  23. //Close the connection with the client
  24. client.close();
  25. }
  26. }
  27. catch (Exception ioe)
  28. {
  29. //In case of exceptions print it to the console.
  30. System.out.println(ioe);
  31. }
  32. }

  33. }
This will now print whatever your browser is asking from your server to the screen.Once again opening http://localhost/ or http://127.0.0.1/ will give you date on the browser and this output on the console.



Now the browser says GET / HTTP/1.1 (Note: The requests may vary dependent upon the browser you use. Mine is chrome by google). Now this request means GET whatever is there in your / directory, i.e., the root directory your server is broadcasting. And HTTP/1.1 is the version and type it supports. Now though most browsers would just display your html file without any problem if transmitted like this.

  1. import java.net.*;
  2. import java.io.*;

  3. public class Server {
  4. public static void main(String[] args)
  5. {
  6. try
  7. {
  8. //Create a socket at port 80. The port over which browser usually connects
  9. ServerSocket sock = new ServerSocket(80);
  10. //Go into a loop and wait for connections to occur
  11. while(true)
  12. {
  13. //Accept a connection
  14. Socket client = sock.accept();
  15. //Create a buffer to read the client request
  16. BufferedReader input = new BufferedReader(new InputStreamReader(client.getInputStream()));
  17. //Print out the requested line
  18. System.out.println(input.readLine());
  19. //Create a output stream to send the file
  20. DataOutputStream output = new DataOutputStream(client.getOutputStream());

  21. //Open a File to send it over the link
  22. FileInputStream indexfile = new FileInputStream("C:\\users\\regnarts\\Desktop\\index.html");
  23. //Buffer for file transfer usage
  24. byte [] buffer = new byte[1024];
  25.         
  26. //loop the transfer mechanism
  27. while (true) 
  28.        {
  29.            //Read and write the file to the buffer
  30. int b = indexfile.read(buffer, 0,1024);
  31.            if (b == -1) {
  32.            break; //end of file
  33.        }
  34.          output.write(buffer,0,b);
  35.        }
  36.                 
  37.       
  38. //Close the file and the output buffer
  39.        output.close();
  40.        indexfile.close();
  41.    //Close the connection with the client
  42.        client.close();
  43. }
  44. }
  45. catch (Exception ioe)
  46. {
  47. //In case of exceptions print it to the console.
  48. System.out.println(ioe);
  49. }
  50. }

  51. }
Edit the file path from my program before you compile it. And create a index.html file (or any other name as long as you are sure that the path points to it). Now if we run the file and open http://localhost/ or http://127.0.0.1/ on browser we get 

For the html file, I copied one from the internet that was meant for a html tutorial from http://www.mcli.dist.maricopa.edu/tut/tut1.html. It reads

  1.  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
  2.      <html>
  3.      <head>
  4.      <title>Volcano Web</title>
  5.      </head>
  6.      <!-- written for the Writing HTML Tutorial
  7.      by Lorrie Lava, February 31, 1999       -->
  8.      <body>
  9.      In this lesson you will use the Internet to research 
  10.      information on volcanoes and then write a report on 
  11.      your results.
  12.      </body>
  13.      </html>
Though this must work on most of the browsers it is not the way a server is expected to respond. The server must first output certain bytes that tells the client, status of its request. Perhaps the most famous of these is the "404 File Not Found " error. The correct output to send the index.html file would be

HTTP/1.0 200 OK\r\n Content-Type: text/html\r\n

followed by the index.html file itself. It is not compulsory to transmit index.html itself. But many webservers use it as a default file to be transmitted at the first connection. Try creating a fully working webserver along with security in either android or java. Use concurrency to create different threads to handle every request. Good Luck!!!