Search code examples
javamultithreadingserversocket

Thread hanging when calling LinkedList.add


So I'm writing two ServerSockets. One that listens for HTTP requests on port 8085 and saves the byte input into a static LinkedList, and a second that listens on port 8086 and returns all the results in the static LinkedList.

The issue is that when saving the data from ServerSocket:8085 to the LinkedList, the thread hangs and I'm not sure why.

This is the main Listener class:

import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.*;

public class Listener {

    public static LinkedList<byte[]> Calls = new LinkedList<>();

    public static void main(String[] args) {
        Thread callback = new Thread(new ThreadListener());
        callback.start();

        while (true) {
            try (var listener = new ServerSocket(8086)) {
                System.out.println("Listening on 8086...");
                try (var client = listener.accept()) {
                    StringBuffer response = new StringBuffer();
                    response.append("HTTP/1.1 200 OK\r\n\r\n");
                    Iterator<byte[]> iterator = Calls.iterator();
                    while (iterator.hasNext()) {
                        response.append(new String(iterator.next(), Charset.forName("UTF-8")) + "\r\n");
                        iterator.remove();
                    }
                    client.getOutputStream().write(response.toString().getBytes("UTF-8"));
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }
}

This is the ThreadListener class:

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Date;

public class ThreadListener implements Runnable {
    @Override
    public void run() {
        while (true) {
            try (var listener = new ServerSocket(8085)) {
                System.out.println("Listening on 8085...");
                try (var socket = listener.accept()) {
                    if (!socket.getInetAddress().getHostAddress().equals("127.0.0.1")) {
                        System.out.println("Not localhost");
                    } else {
                        System.out.println("Its us!");
                    }
                    Listener.Calls.add(socket.getInputStream().readAllBytes());
                    System.out.println("Result collected");
                    Date today = new Date();
                    String httpResponse = "HTTP/1.1 200 OK\r\n\r\n" + today;
                    socket.getOutputStream().write(httpResponse.getBytes("UTF-8"));
                    socket.close();
                }

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

As for my test, I tried calling 127.0.0.1:8085, and I get an ERR_CONNECTION_RESET, and all I have in the console is the following:

Listening on 8085...
Listening on 8086...
Its us!

Process finished with exit code -1 (I killed the app after 2 mins)

The fact that the "Its us!" message got printed, but the "Results collected!" right after the LinkedList.add didn't is what leads me to assume the LinkedList.add is the one hanging the thread.

Regards

EDIT: No one is calling to 8085 (or 8086), I'm doing it manually on my browser. I solved the Syncronization issue by creating a method to call instead of calling the LinkedList.add directly:

    public static synchronized void addElementsToList(byte[] bytes) {
        Calls.add(bytes);
    }

This does work, but calling the 8085 socket gives the connection reset every time.


Solution

  • Your test mechanism of using a browser to create the request is probably also not helping here, as the InputStream.readAllBytes()

    blocks until all remaining bytes have been read and end of stream is detected, or an exception is thrown. This method does not close the input stream.

    From the documentation. Specifically, the browser is keeping the connection open, because it's expecting some response. Your server is trying to read everything from the connection until the connection is closed. Catch 22 (aka deadlock).

    Try making the connection to localhost:8085 using telnet and closing the connection from the client end.

    telnet 127.0.0.1 8085
    
    ^D
    

    where ^D is literally the [CTRL] and [D] keys (eg: logout)