Java SocketServer with multiple clients - StreamCorruptException - java

The Application
I'm writing a client/server application in Java, that communicates by sending objects over sockets using the ObjectStream classes. Each node in the application looks approximately like this:
class Node {
SocketServer server;
Socket[] clients;
}
Here the server variable is the socket on which this node listens, and the client variables are the sockets on which other nodes listen, and to which this node sends objects.
The code that I use to write objects to one of the client sockets looks like this:
void sendMessage(Message<B, F> msg) throws IOException {
ObjectOutputStream writer = getWriter();
writer.writeObject(msg);
writer.flush();
}
private ObjectOutputStream writer;
ObjectOutputStream getWriter() throws IOException {
if (writer == null)
writer = new ObjectOutputStream(
new BufferedOutputStream(client.getOutputStream()));
return writer;
}
And the code that I use to handle connections and read objects from the node's server socket looks like this:
// the handler will listen for connections
final Thread handler = new Thread(new Runnable() {
public void run() {
try {
// create a new thread to handle the client
final Socket client = server.accept();
final Thread thread = new Thread(new Runnable() {
public void run() {
final ObjectInputStream reader;
try {
reader = new ObjectInputStream(client.getInputStream());
while (true) {
try {
val msg = reader.readObject();
messages.add((Message<B, F>) msg);
}
catch (EOFException e) {
// i noted it seemed to throw eofexceptions
}
catch (IOException e) {
// do something
}
}
}
catch (IOException e) {
// do something
}
}
});
thread.start();
} catch (IOException e) {
// do something
}
}
});
handler.start();
The Problem
I think I'm doing something wrong with the sockets here. Everything works fine when every server is only connected to a single client. However, when multiple clients are talking to the same server things go bad, and I get StreamCorruptedException's from the ObjectInputStream and other strange behaviour (putting in an instance of an UpdateRequest message, and getting out an instance of Integer(0) and some exceptions, for example.)
My intuition tells me that somehow the two object/byte streams are getting intermingled, and this produces the strange results when attempting to deserialize the objects. My question is: why is this happening aka what am I doing wrong, and how could I fix it?

You have an array of Sockets but you don't appear to have an array of writers and readers. So you're probably using the same writer and reader for all connections.
Really you should have a per-connection Connection object, that implements Runnable, and that has the Socket, the writer, and the reader as instance members.
Also when you catch EOFException you must break out of the loop and close the writer.

The problem was occurring due to messages being sent simultaneously, and this resulted in the bytes being mixed. The solution was to make sure that messages would only be received one at a time.

Related

Multithreaded Server with AsynchronousServerSocketChannel

I have to implement a Server which should accept more connections. Without any deeper thoughts i decided to use the new JAVA NIO.2 classes.
My current approach is:
final Semaphore wait = new Semaphore(1);
while(true){
wait.acquire();
this.asyncSocket.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
#Override
public void completed(AsynchronousSocketChannel result, Void attachment) {
wait.release();
asyncSocket.accept(null, this);
...
}
...
}
}
if i don't add the semaphore, i get an AcceptPendingException. It works, however, i don't know if thats the proper way to implement a server which can handle more open sockets.
Another Approach was:
final Semaphore wait = new Semaphore(1);
while(true){
wait.acquire();
final Future<AsynchronousSocketChannel> futureChannel = this.asyncSocket.accept();
this.exec.execute(new Runnable() {
#Override
public void run() {
try (final AsynchronousSocketChannel clientChannel = futureChannel.get()) {
wait.release();
try (ObjectInputStream ois = new ObjectInputStream(Channels.newInputStream(clientChannel))) {
final Command cmd = (Command) ois.readObject();
cmd.execute(util, clientChannel, null, logger).run();
}
} catch (IOException | InterruptedException | ClassNotFoundException | ExecutionException e) {
e.printStackTrace();
}
}
});
Why i'm unhappy with both solutions?
Unfortunately, in both implementations, the server leaves a lot of open sockets in state TIME_WAIT, although i'm closing the it on the server as well on the client side..
So actually i've 2 questions:
Whats a proper way to use AsynchronousServerSocketChannel to implement a Server wich accepts more connections.
How to get rid of the open sockets in state TIME_WAIT
EDIT:
private <T extends Serializable> T sendCommand(final Command<T> command) throws ExecutionException, InterruptedException, IOException, ClassNotFoundException {
T result = null;
try (final AsynchronousSocketChannel channel = AsynchronousSocketChannel.open(channelGroup)) {
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.connect(this.mwInfo.getNextMiddleware()).get();
final OutputStream os = Channels.newOutputStream(channel);
final InputStream is = Channels.newInputStream(channel);
try (final ObjectOutputStream oos = new ObjectOutputStream(os)) {
oos.writeObject(command);
oos.flush();
try (final ObjectInputStream ois = new ObjectInputStream(is)) {
result = (T) ois.readObject();
}
}
}
return result;
}
Thanks in advance!
I can only answer the second question (no knowledge of Java socket specifics). To get rid of those sockets you must implement 'graceful shutdown' protocol on socket. That is, one socket does shutdown on send, another one does shutdown on send upon seing that, than sockets to shutdown on recv. This will ensure no sockets will stay in TIME_WAIT state.
The other option would be to fiddle with SO_LINGER option of the socket, but this is ill-advised.
I also notice, that people seems to just use SO_REUSEADDR as a universal solution. You can't bind to a port? Specify SO_REUSEADDR and all your problems will go away... and this is wrong! If SO_REUSEADDR is universal solution, why is it not ON by default? Because it is dangerous. When you specify SO_REUSEADDR, you create another socket on the same port and now you can start seeing messages from the previous connection! This is not very likely to happen, of course. But it can happen! Imagine what kind of bug would it be to troubleshoot!

manage socket connection in Java over tcp

I wrote a client which basically just open a socket and send content over the connection. ( the content follows the Http protocol)
The problem I'm facing regards to the question - how and when should i close the connection.
The issue is that the connection sometime closes too early ("FIN" is sent to the server before the server answered).
in this case the server's answer is lost.
I tried to use Thread.sleep before closing the connection but nothing seems to affect the time between the content is sent and the "FIN" message is sent. (viewed in Wireshark)
The answer sometimes arrive and sometimes not ( race condition).
How can i delay the "FIN" message so i won't miss the server's response?
i added the relevant class. The relevant function is sendContentOverSocket
public class SocketClient {
private String hostName;
private int portNumber;
private Socket ConnectionSocket;
public void init(String hostName, int portNumber){
this.hostName = hostName;
this.portNumber = portNumber;
this.ConnectionSocket=createSocketConnection();
}
private Socket createSocketConnection() {
Socket socket = null;
try {
socket = new Socket(this.hostName, this.portNumber);
return socket;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return socket;
}
public void sendContentOverSocket(String content) {
try {
PrintWriter out = new PrintWriter(
ConnectionSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
ConnectionSocket.getInputStream()));
out.print(content);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.close();
in.close();
ConnectionSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
TCP works with a concept called a half close.
When you close the socket that is an indication that you are not going to send anymore.
In your explanation I see "FIN is sent to the server before the server answered", if you are the client, that would mean that you have performed a close on the socket.
If you expect a result from a server within a certain time frame you need some kind of timing mechanism, possibly making use of select in combination with a timeout.
If the server closes his end of the connection, you detect this by receiving bytes in receive. Usually this means that you have to close the socket too.
So in conclusion there is 3 reasons for you to close the socket :
the server closes his end of the socket basically saying i am not going to send anymore
you have waited for a while and you are tired of waiting and decide to close the socket yourself.
any other error conditions but usually they all appear like receiving 0 bytes or a negative number.
You should close the connection after you've read the response, of course. Difficult to see the mystery here. No sleeps. If you don't read the response (a) you can't know whether the request succeeded or failed, and (b) the server is liable into encounter an exception as well.
Your code is poor quality. All those methods should propagate exceptions instead of catching them internally and returning null.
In case of Java 7, since all three classes, i.e. Socket, PrintWriter, BufferedReader, implement AutoCloseable and based on the fact, that you want to close socket right after you invoke sendContentOverSocket(String content) try to use the following code:
public class SocketClient {
private String hostName;
private int portNumber;
public void init(String hostName, int portNumber) {
this.hostName = hostName;
this.portNumber = portNumber;
}
public void sendContentOverSocket(String content) {
try (Socket socket = new Socket(this.hostName, this.portNumber);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
out.print(content);
} catch(IOException e) {
//Appropriate exception handler
}
}
}
In this case Java will close all resources properly by itself.
If you use Java 6 or earlier try to use try-finally block instead:
solved.
i now understand how it works.
what i was missing in the client is the attempt to read from the input Stream.
When you try to read
while ((inputFromServer = in.readLine()) != null)
the client waits for input. The only thing that will break this loop is the server closing the connection.
after that happens you can safely close the connection on the client side. No need to delay the FIN and such...

Java Sockets listener

Would it be appropriate to use a thread to get objects received by a socket's InputStream and then add them to a ConcurrentLinkedQueue so that they can be accessed from the main thread without blocking at the poll-input loop?
private Queue<Packet> packetQueue = new ConcurrentLinkedQueue<Packet>();
private ObjectInputStream fromServer; //this is the input stream of the server
public void startListening()
{
Thread listeningThread = new Thread()
{
public void run()
{
while(isConnected()) //check if the socket is connected to anything
{
try {
packetQueue.offer((Packet) fromServer.readObject()); //add packet to queue
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
listeningThread.start(); //start the thread
}
public Packet getNextPacket()
{
return packetQueue.poll(); //get the next packet in the queue
}
It depends on what you need to do with this object that you'll use in main thread.
If need sometime to process it or if it'll be used many times than you can put it in a queue or in another class that will hold this object for you, but if the time you need to process it is low you and you don't need this object further after processing you don't really need to use a queue.
About using the ConcurrentQueue depends too, you need order? you need guarantee synchronism between the read and the write?
You can use Asynchronous socket too to handle many clients and process in the same thread or even getting the objects from them and throwing in a queue to further process.
But "be appropriate" is hard to answer because depends on what you need to do with this objects and how you'll handle it.

Java waiting for client's data pauses application cause of infinite loop

hey I am trying to make a console application that can receive and send messages to the clients.
It will accept multiple clients & handle them.
To add a new client i do this in the run method:
#Override
public void run() {
try {
this.server = new ServerSocket(this.port);
this.factory = new ServerFactory(this.server);
System.out.println("Server runs and now waiting for clients");
this.runClientHandler();
Socket client;
while ((client = this.server.accept()) != null) {
this.handler.addClient(this.factory.createClient(client));
System.out.println("done");
}
} catch (IOException e) {
e.printStackTrace();
}
}
But "done" will never be printed because of this client's infinite loop for his message:
public void handleClient() throws IOException {
byte[] buffer = new byte[5*1024];
int read = -1;
byte[] data;
String message;
while ((read = this.socket.getInputStream().read(buffer)) > -1) {
data = new byte[read];
System.arraycopy(buffer, 0, data, 0, read);
message = new String(data, "UTF-8");
System.out.println("Client message: " + message);
}
}
handleClient() method will run in Thread-2 at handleClients.add():
public void addClient(Client c) throws IOException {
c.writeMessageStream("hey");
System.out.println("New client!");
this.clients.add(c);
//prints here
c.handleClient();
//never reaches this..
}
How can I ignore the while loop and let the program execute while the while loop runs without making a new thread for each client?
Check NIO Selectors. They are part of Java NIO in JDK. Or you can use an out-of-the-box solutions like Netty or (worse) Apache MINA.
Your code won't be able to handle multiple clients as it is serving the client from the same thread it is accepting connections. Generally, the client connections should be handled by different threads and you may like to use asynchronous IO so that multiple connections can be handled from a single thread. You should use Netty which simplified all these. Here are some example programs http://netty.io/5.0/xref/io/netty/example/telnet/package-summary.html

Get messages from thread

In First class have method "listen" which listening client socket
public void listen() throws IOException {
while (true) {
socket = this.serverSocket.accept();
DataOutputStream out = new DataOutputStream( socket.getOutputStream() );
this.outputStreams.put(socket, out);
Thread miltiServer;
miltiServer = new Thread() {
#Override
public void run() {
InputStream sin = null;
try {
sin = socket.getInputStream();
ObjectInputStream in = new ObjectInputStream(sin);
message = (AgentData) in.readObject();
} catch (ClassNotFoundException ex) {
} catch (IOException ex) {
}
}
};
miltiServer.start();
}
In Second class i need to read and analyze messages which recieved from client socket. I don't know how to get messages in other class. I have idea to use Callable interface, but if i use it, return statement will exit from infinitive cycle.
An easy way for your socket listener to communicate the messages to your Second class is through a BlockingQueue. The listener would read from the socket input stream and call queue.put(...) to add any messages to the queue.
Then the Second class would be in a loop calling queue.take(); which would return each message when it is added to the queue. If you want unlimited messages to be queued then LinkedBlockingQueue would work. If you want to throttle the messages then a bounded queue such as ArrayBlockingQueue might be more appropriate.
Both threads would need to share the same BlockingQueue so you will need to construct it and pass it to both threads or put a method on your Second class named something like addMessage(...) and the BlockingQueue would be inside of your Second class. Then the listener would call second.addMessage(...);.

Categories

Resources