Saturday, August 16, 2014

Implement simple HTTP server running on Android

Example to implement simple HTTP server on Android:


MainActivity.java
package com.example.androidhttpserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.support.v7.app.ActionBarActivity;
import android.widget.EditText;
import android.widget.TextView;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

 EditText welcomeMsg;
 TextView infoIp;
 TextView infoMsg;
 String msgLog = "";
 
 ServerSocket httpServerSocket;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  welcomeMsg = (EditText) findViewById(R.id.welcomemsg);
  infoIp = (TextView) findViewById(R.id.infoip);
  infoMsg = (TextView) findViewById(R.id.msg);

  infoIp.setText(getIpAddress() + ":" 
   + HttpServerThread.HttpServerPORT + "\n");

  HttpServerThread httpServerThread = new HttpServerThread();
  httpServerThread.start();
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();

  if (httpServerSocket != null) {
   try {
    httpServerSocket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }
 
 private class HttpServerThread extends Thread {
  
  static final int HttpServerPORT = 8888;

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    httpServerSocket = new ServerSocket(HttpServerPORT);
    
    while(true){
     socket = httpServerSocket.accept();

     HttpResponseThread httpResponseThread = 
      new HttpResponseThread(
       socket, 
       welcomeMsg.getText().toString());
     httpResponseThread.start();
    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

  }

  
 }
 
 private class HttpResponseThread extends Thread {
  
  Socket socket;
  String h1;
  
  HttpResponseThread(Socket socket, String msg){
   this.socket = socket;
   h1 = msg;
  }

  @Override
  public void run() {
   BufferedReader is;
   PrintWriter os;
   String request;
   
   
   try {
    is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    request = is.readLine();
    
    os = new PrintWriter(socket.getOutputStream(), true);
    
    String response = 
     "<html><head></head>" +
     "<body>" +
     "<h1>" + h1 + "</h1>" +
     "</body></html>";
    
    os.print("HTTP/1.0 200" + "\r\n");
    os.print("Content type: text/html" + "\r\n");
    os.print("Content length: " + response.length() + "\r\n");
    os.print("\r\n");
    os.print(response + "\r\n");
    os.flush();
    socket.close();
    
    
    msgLog += "Request of " + request 
      + " from " + socket.getInetAddress().toString() + "\n";
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      
      infoMsg.setText(msgLog);
     }
    });
    
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   return;
  }
 }

}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <EditText
        android:id="@+id/welcomemsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Welcome from Android-er" />

    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:id="@+id/msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

download filesDownload the files.

Related:
Simple web server using org.apache.http.protocol.HttpService

Updated@2015-11-25:
Permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

Updated@2015-11-26:
This code NOT work on Android 5, may be all 5+ version.
Fixed, refer post "socket.getInetAddress() return null on Android 5".

11 comments:

  1. your blog is best.....
    how to share external storage directory and make them downloadable from pc... like wifi file sharing applications

    ReplyDelete
  2. Great Tutorial
    Please sir/mam
    how to share external storage directory and make them downloadable from pc... like wifi file sharing applications

    ReplyDelete
  3. I guess it will also require internet permission

    in AndroidManifest.xml

    ReplyDelete
  4. How to send image through socket and user can download from it?

    ReplyDelete
  5. this application is not working as shown in the video. I added a few permissions to manifest file but still i don't get logs on the screen. Can anyone help?

    ReplyDelete
  6. Dont socket.close() before reading InetAddress.

    ReplyDelete
  7. hello Mridul Gupta,

    Yes, I already Updated@2015-11-26:
    This code NOT work on Android 5, may be all 5+ version.
    Fixed, refer post "socket.getInetAddress() return null on Android 5".

    ReplyDelete
  8. Just 2 small details:
    1) don't forget to add ":8888" after the IP on the URL you write in your browser
    2) if you use the server from a browser on local network, eveything's OK. But if you use it throught a Javascrit call, using XMLHttpRequest you'll receive... nothing! In fact the server send a http.readyState at 4 (everything OK) but a http.status at 0 rather than 200. To get a http.status at 200 you must add a line in the header sended by the server. You must have:
    os.print("HTTP/1.1 200 OK" + "\r\n");
    os.print("Access-Control-Allow-Origin: *" + "\r\n");
    Hope this will help.

    ReplyDelete
  9. @Andr.oid Eric. I think you have a config problem in your dev tool (Android Studio?). Because I use this small web server on a Samsung Galaxy TAB E running Android 4.4 and on a Samsung J2 running 6.01 and in both cases, it work like a charm. I tried it also on a really bad and old "low quality Chinese smartphone" and it works too.

    ReplyDelete
  10. Thank you very much..
    It helped and exactly what i was looking for..
    Can we use post instead of get to post additional data.
    Thanks again.

    ReplyDelete
  11. used as sample. worked at first run,but not inside the emulator. only on real hardware.

    ReplyDelete