I'm creating a multithreaded chat server that supposed to create a separate thread for each connected client. Every time a client connects, my server creates a new instance of a client handler class, that is supposed to keep track for ingoing and outgoing messages from/to that specific client.
The first time a client connects to my echo server, the server will respond with an echo of the clients response. But if I try to send a message to the server a second time, the client creates an IOException. I have the created the client application myself, but I know it works because I can communicate with other servers just fine. I'm pretty sure the problem is somewhere in the run method of this client handler class, but I can't figure out why it's not working. Here's the run method in my client handler class:
public void run() {
try (
BufferedReader in =
new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream());
) {
long time = System.currentTimeMillis();
out.println("Server - " + time + ": " + in.readLine());
out.close();
try {
in.close();
} catch (IOException e) {
System.err.println("Couldn't close input stream");
}
} catch(IOException e) {
System.err.println("Got an IOException error while reading or writing from/to client");
}
}
I've guessed that I'm supposed to have some kind of while loop somewhere, but all of my attempts to implement this have failed. E.g. I've tried to change this code:
long time = System.currentTimeMillis();
out.println("Server - " + time + ": " + in.readLine());
To this:
String inputLine;
while((inputLine = in.readLine()) != null) {
long time = System.currentTimeMillis();
out.println("Server - " + time + ": " + inputLine);
}
This solution is more or less a copy of how the oracle site (http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html) says it's supposed to be done.
I think the main problem might be me not really grasping the whole concept of server/client communication, so a push in the right direction would be greatly appreciated.
Thanks in advance!
The important bit in the Oracle article you mention is the part titled - Supporting Multiple Clients.
The basic Java socket API is a blocking API, which basically means you call a method and that method blocks until an IO event happens. If you need to wait for multiple IO events - in your case an incoming client connection and incoming data - you have to create multiple threads.
The server shown in the article only accepts a single incomming (client) connection and will close once the client closes because the InputStream
on the server will return null
causing the loop to terminate.
First your server needs to look something like this (which is simplified example):
try (ServerSocket serverSocket = new ServerSocket(portNumber))
{
while (running)
{
Socket clientSocket = serverSocket.accept();
new Thread(new ClientHandler(clientSocket)).start();
}
}
Note: starting a thread for each client connection demonstrates the point but is a vast over simplification of managing the connection load on a server.
The client code can remain as is.
That's the basics that as I pointed out leaves the thread management in the developers hands - this often leads to trouble because people simply get it wrong. Because of this Java's socket APIs have been extended to create the NIO API - Jakob Jenkov has written some good tutorials.
It's also worth looking at Netty, which personally I think is easier to use than NIO.