George R. George R. - 1 month ago 6
Java Question

Java while(true) loop executes only once inside thread

I am trying to implement a simple client-server application in Java.

Here is the code:

Client.java

public class Client implements Runnable {
private String hostName;
private int portNumber;
private String message;

private Socket socket;
private PrintWriter writer;
private BufferedReader reader;

public Client(String hostName, int portNumber, String message) {
this.hostName = hostName;
this.portNumber = portNumber;
this.message = message;
}

public void connect() {
try {
socket = new Socket(hostName, portNumber);
writer = new PrintWriter(socket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

writer.println(message);
} catch (UnknownHostException e) {
System.err.println("Could not resolve the host name '" + hostName + "'.");
} catch (IOException e) {
System.err.println("Could not get the I/O for the connection to '" + hostName + "'.");
}
}

private void listenForMessages() {
while (true) {
try {
System.out.println("In loop!");
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}

public void run() {
connect();
listenForMessages();
}
}


Server.java

public class Server implements Runnable {
private int portNumber;
private String message;

private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter writer;
private BufferedReader reader;

public Server(int portNumber, String message) {
this.portNumber = portNumber;
this.message = message;
}

private void listen() {
try {
serverSocket = new ServerSocket(portNumber);
} catch (IOException e) {
System.err.println(e.getMessage());
}

while (true) {
try {
clientSocket = serverSocket.accept();
writer = new PrintWriter(clientSocket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}

writer.println(message);
} catch (IOException e) {
System.err.println(e.getMessage());
break;
}
}
}

public void run() {
listen();
}
}


And this is the main class:

public class Test {
public static void main(String[] args) {
Client client = new Client("localhost", 4444, "Hello from client!");
Server server = new Server(4444, "Hello from server!");

Thread serverThread = new Thread(server);
serverThread.start();

Thread clientThread = new Thread(client);
clientThread.start();
}
}


The logic of the code is simple: both the client and the server are waiting for messages inside a
while(true)
loop.

The
while
loop inside the server's
listen
method executes just fine. However, inside the
listenForMessages
method, the loop seems to be executed only once. I only see one "In loop" printed on the screen.

Can you figure out what the problem is?

Thank you in advance!

Answer

However, inside the listenForMessages method, the loop seems to be executed only once. I only see one "In loop" printed on the screen.

Actually it is not because the loop is executed only once it is simply because reader.readLine() will make the current thread wait until it receives an entire line and here if you check the code of the Server, it reads first and it reads in an infinite loop as reader.readLine() will only return null at the end of the stream so when the socket will be closed in this case.

If you want to implement some kind of ping-pong between the client and the server, simply read then write on one side and write and read and the other side as next:

Client code:

public void connect() {
    try {
        socket = new Socket(hostName, portNumber);
        writer = new PrintWriter(socket.getOutputStream(), true);
        reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    } catch (UnknownHostException e) {
        System.err.println("Could not resolve the host name '" + hostName + "'.");
    } catch (IOException e) {
        System.err.println(
            "Could not get the I/O for the connection to '" + hostName + "'."
        );
    }
}

private void listenForMessages() {
    while (true) {
        try {
            System.out.println("In loop!");
            // Write the message for the server
            writer.println(message);
            // Read the message from the server
            System.out.println(reader.readLine());
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }
}

Server code:

while (true) {
    try {
        clientSocket = serverSocket.accept();
        writer = new PrintWriter(clientSocket.getOutputStream(), true);
        reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

        while (true) {
            // Read the message from the client
            System.out.println(reader.readLine());
            // Write the message for the client
            writer.println(message);
        }


    } catch (IOException e) {
        System.err.println(e.getMessage());
        break;
    }
}

Output:

In loop!
Hello from client!
Hello from server!
In loop!
Hello from client!
Hello from server!
...