Erich
Erich

Reputation: 53

Android socket behaves strangely after Wi-Fi connection is reset

I am currently working on a research project that requires me to execute the following protocol in Android:

  1. Establish a connection with an arbitrary web server (3-way handshake) using Wi-Fi
  2. Disconnect and reconnect to the same Wi-Fi access point
  3. Send an HTTP GET request using Wi-Fi

I have managed to execute this protocol using C (in a Linux environment) and Java (in a Windows environment). However, when I try to do the same thing in Android using the following code, I am unable to send the HTTP GET request after disconnecting and reconnecting to the same Wi-Fi access point.

try {
    // executes 3-way handshake
    Socket socket = new Socket(InetAddress.getByName("www.google.com"), 80);

    // disconnects/reconnects to WiFiAP
    WifiManager wifiManager = (WifiManager) baseActivity.getSystemService(Context.WIFI_SERVICE);
    wifiManager.disconnect();
    Thread.sleep(3000);
    wifiManager.reconnect();
    Thread.sleep(3000);

    // sends HTTP GET request
    PrintWriter pw = new PrintWriter(socket.getOutputStream());
    pw.println("GET / HTTP/1.1");
    pw.println("Host: www.google.com");
    pw.println("");
    pw.flush();

    // prints web server response to display
    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String t;
    while ((t = br.readLine()) != null) {
        outputResults(t);
    }
    br.close();

} catch (UnknownHostException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (InterruptedException e) {
    e.printStackTrace();
}

Wireshark shows that the 3-way handshake is successfully executed. However, after disconnecting/reconnecting to the access point, the output stream in never flushed. Initially, I thought the problem might be due to a timeout. However, if instead of disconnecting/reconnecting to the Wi-Fi access point I introduce an equivalent time delay, the code works fine.

I have been stuck on this one for about a week. Any help is greatly appreciate!

Upvotes: 2

Views: 970

Answers (1)

Seraphim's
Seraphim's

Reputation: 12768

Welcome to the Android WiFi socket hell. I usually recognize that the underlying connection have been interrupted by catching th exception and searching into the exception message for the text "broken pipe":

if (socketException.getMessage().toLowerCase().contains("broken pipe")) {
    forceReconnection();
}

so forceReconnection() clear the in/out buffer:

protected void disposeIO() {

    // shoutdown socket IO
    try {
        socket.shutdownInput();
    } catch (Exception e) {
    }

    try {
        socket.shutdownOutput();
    } catch (Exception e) {
    }

    try {
        this.inputReader.close();
        this.inputReader = null;
    } catch (Exception e) {
    }

    // close out stream
    try {
        outputStream.close();
        outputStream = null;
    } catch (Exception e) {
    }
}

and re-establish the connection to my endpoint calling socket.close() and recreating socket, the input reader, output stream

Upvotes: 1

Related Questions