Thursday, November 26, 2015

socket.getInetAddress() return null on Android 5

Refer to last example of "Simple HTTP server running on Android", it work on Xiaomi Redmi 2 running Android 4.4.4. But somebody report program stopped on Android 5 devices. So I re-test on Nexus 7 running Android 5.1.1. Yes, the app crash! caused by NullPointerException, because socket.getInetAddress() return null.


Modify MainActivity.java to capture socket.getInetAddress() before and after close():
package com.blogspot.android_er.androidhttpserver;

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

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;

public class MainActivity extends AppCompatActivity {

    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();
                InetAddress clientInetAddressBeforeClose = socket.getInetAddress();
                socket.close();
                InetAddress clientInetAddressAfterClose = socket.getInetAddress();

                msgLog += "Request: " + request + "\n";

                if(clientInetAddressBeforeClose == null){
                    msgLog += "clientInetAddressBeforeClose == null\n";
                }else{
                    msgLog += "clientInetAddressBeforeClose = " + clientInetAddressBeforeClose.toString() + "\n";
                }

                if(clientInetAddressAfterClose == null){
                    msgLog += "clientInetAddressAfterClose == null\n";
                }else{
                    msgLog += "clientInetAddressAfterClose = " + clientInetAddressAfterClose.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;
        }
    }
}


It's found that on Xiaomi Redmi 2 running Android 4.4.4, socket.getInetAddress() keep no change before and after close().


But on Nexus 7 running Android 5.1.1, change to null after close().


So, we have to read socket.getInetAddress() before close().

3 comments:

snow said...

This tutorial is so great.
and now, I have a problem: how to keep the server alive using service, even quit the server app.

Erik said...

hello Snow Necs,

If you want to run a long-running operations in the background, you can use Service. Service is a big topic, it is suggested to read the official API Guides, Services.

It's my simple example of using Service and BroadcastReceiver

ECOWORLD said...

Great tutorial, how can I serve files instead of html code?