Java NIO - gracefully closing connection on the client side - java

When using NIO, I have the following checks on the server side:
if (key.isReadable()) {
readBuffer.clear();
SocketChannel channel = (SocketChannel) key.channel();
int read = channel.read(readBuffer);
if (read == -1) {
channel.close();
channel.keyFor(selector).cancel();
} else {
readBuffer.flip();
System.out.println(charset.decode(readBuffer));
}
}
However, it is often the case that read will throw java.io.IOException: An existing connection was forcibly closed by the remote host. On the client side, this is what I do to close the connection:
public void close() throws IOException {
connection.close();
connection.keyFor(selector).cancel();
selector.close();
}
If that is not the graceful way, what is?

The server should send a message to the client to close its connection. It can only do this if the buffers are not full, but it will allows the client to gracefully close the connection.
A simpler solution is for the client to expect this exception and handle it silently. However, the poison pill message is more reliable IMHO as you can tell whether the connection was intended to be closed by the server.
BTW The client can send the same message to the server. After sending the message, you might want to wait for the other end to hang up before closing the connection yourself (or timing out)

You get this exception if you have written to the connection after the peer had already closed it. In other words, an application protocol error.
Solution: don't.

Related

ServerSocket times out and exits server program

I'm trying to implement a server that accepts connections but times out and closes that specific connection only if it hasn't received anything from that connection after N milliseconds.
From my possible misunderstanding of ServerSocket's setSoTimeout(int milliseconds) method, I thought this behaviour could be accomplished by passing N to setSoTimeout.
What I'm experiencing is once a client makes a connection, and doesn't send anything over that connection for N seconds, the server catches a SocketTimeoutException, but then completely stops execution and ends the process running the server program. Here is my server's listen method:
private static void listen() throws IOException {
while(true) {
try {
Socket clientSocket = serverSocket.accept();
Connection connexion = new Connection(clientSocket);
connexion.start();
} catch (SocketTimeoutException e) {
System.out.println("Socket timed out!");
break;
}
}
}
I successfully catch the SocketTimeoutException, ignore it (bad I know!) and assume that the client connection that caused the exception gets closed. Then I just break out of the catch block to continue accepting other client connections. What am I missing here?
You need to add continue; instead of break; in the try-catch clause. The server will keep listening.
assume that the client connection that caused the exception gets closed.
Incorrect assumption. The accept() is what has timed out. The client connection hasn't done anything yet.
Then I just break out of the catch block to continue accepting other client connections.
Err, no, you break out of the catch block to stop accepting other client connections. You're breaking out of the accept loop.
What am I missing here?
A continue instead of a break.
If you don't care about the SocketTimeoutException why are you setting a socket timeout on the ServerSocket? Just remove that.

Keep Socket Server Open After Client Closes

I have implemented a socket with a server and single client. The way it's structured currently, the server closes whenever the client closes. My intent is have the server run until manual shutdown instead.
Here's the server:
public static void main(String args[])
{
;
try
{
ServerSocket socket= new ServerSocket(17);
System.out.println("connect...");
Socket s = socket.accept();
System.out.println("Client Connected.");
while (true)
{
work with server
}
}
catch (IOException e)
{
e.getStackTrace();
}
}
I've tried surrounding the entire try/catch loop with another while(true) loop, but it does nothing, the same issue persists. Any ideas on how to keep the server running?
It looks like what's going to happen in your code there is that you connect to a client, infinitely loop over interactions with the client, then when someone disrupts the connections (closes clearning, or interrupts it rudly - e.g., unplug the network cable) you're going to get an IOException, sending you down to the catch clause which runs and then continues after that (and I'm guessing "after that" is the end of your main()?)...
So what you need to do is, from that point, loop back to the accept() call so that you can accept another, new client connection. For example, here's some pseudocode:
create server socket
while (1) {
try {
accept client connection
set up your I/O streams
while (1) {
interact with client until connection closes
}
} catch (...) {
handle errors
}
} // loop back to the accept call here
Also, notice how the try-catch block in this case is situated so that errors will be caught and handled within the accept-loop. That way an error on a single client connection will send you back to accept() instead of terminating the server.
Keep a single server socket outside of the loop -- the loop needs to start before accept(). Just put the ServerSocket creation into a separate try/catch block. Otherwise, you'll open a new socket that will try to listen on the same port, but only a single connection has been closed, not the serverSocket. A server socket can accept multiple client connections.
When that works, you probably want to start a new Thread on accept() to support multiple clients. Simplest way to do so is usually to add a "ClinentHandler" class that implements the Runnable interface. And in the client you probably want to put reading from the socket into a separate thread, too.
Is this homework / some kind of assignment?

ObjectInputStream's readObject() freezes after Client Socket connection is killed

I have following Socket server's code that reads stream from connected Socket.
try
{
ObjectInputStream in = new ObjectInputStream(client.getInputStream());
int count = 10;
while(count>0)
{
String msg = in.readObject().toString(); //Stucks here if this client is lost.
System.out.println("Client Says : "+msg);
count--;
}
in.close();
client.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
And I have a Client program, that connects with this server, sends some string every second for 10 times, and server reads from the socket for 10 times and prints the message, but if in between I kill the Client program, the Server freezes in between instead of throwing any exception or anything.
How can I detect this freeze condition? and make this loop iterate infinitely and print whatever client sends until connection is active and stable?
The problem is that the server side of the socket has no way of knowing that the client connection closed because the client code terminates without calling .close() on the client side of the socket, and therefore never sends the TCP FIN signal.
One possible way of fixing this would be to create a new Watcher thread that just periodically inspects the socket to see if it is still active. The problem with that approach is that the isConnected() on the Socket will not work for the same reason stated above so the only real way to inspect the connection is to attempt to write to it. However, this may cause random garbage to be sent to a potentially listening client.
Other options would be to implement some type of keep-alive protocol that the client should agree to (i.e., send keep-alive bits every so often so the Watcher has something to look for). You could also just move to the java.nio approach, which I believe does a better job at dealing with these conditions.
This thread is old, but provides more detail: http://www.velocityreviews.com/forums/t541628-sockets-checking-for-dropped-connections-and-close.html.

ObjectInputStream.readObject() hangs forever during the process of socket communication

I have encountered a problem of socket communication on linux system, the communication process is like below: client send a message to ask the server to do a compute task, and wait for the result message from server after the task completes.
But the client would hangs up to wait for the result message if the task costs a long time such as about 40 minutes even though from the server side, the result message has been written to the socket to respond to the client, but it could normally receive the result message if the task costs little time, such as one minute. Additionally, this problem only happens on customer environment, the communication process behaves normally in our testing environment.
I have suspected the cause to this problem is the default timeout value of socket is different between customer environment and testing environment, but the follow values are identical on these two environment, and both Client and server.
getSoTimeout:0
getReceiveBufferSize:43690
getSendBufferSize:8192
getSoLinger:-1
getTrafficClass:0
getKeepAlive:false
getTcpNoDelay:false
the codes on CLient are like:
Message msg = null;
ObjectInputStream in = client.getClient().getInputStream();
//if no message readObject() will hang here
while ( true ) {
try {
Object recObject = in.readObject();
System.out.println("Client received msg.");
msg = (Message)recObject;
return msg;
}catch (Exception e) {
e.printStackTrace();
return null;
}
}
the codes on server are like,
ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
socketOutStream.writeObject(msgJobComplete);
}catch(Exception e) {
e.printStackTrace();
}
in order to solve this problem, i have added the flush and reset method, but the problem still exists:
ObjectOutputStream socketOutStream = getSocketOutputStream();
try {
MessageJobComplete msgJobComplete = new MessageJobComplete(reportFile, outputFile );
socketOutStream.flush();
logger.debug("AbstractJob#reply to the socket");
socketOutStream.writeObject(msgJobComplete);
socketOutStream.reset();
socketOutStream.flush();
logger.debug("AbstractJob#after Flush Reply");
}catch(Exception e) {
e.printStackTrace();
logger.error("Exception when sending MessageJobComplete."+e.getMessage());
}
so do anyone knows what the next steps i should do to solve this problem.
I guess the cause is the environment setting, but I do not know what the environment factors would affect the socket communication?
And the socket using the Tcp/Ip protocal to communicate, the problem is related with the long time task, so what values about tcp would affect the timeout of socket communication?
After my analysis about the logs, i found after the message are written to the socket, there were no exceptions are thrown/caught. But always after 15 minutes, there are exceptions in the objectInputStream.readObject() codes snippet of Server Side which is used to accept the request from client. However, socket.getSoTimeout value is 0, so it is very strange that the a Timed out Exception was thrown.
{2012-01-09 17:44:13,908} ERROR java.net.SocketException: Connection timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:146)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:312)
at sun.security.ssl.InputRecord.read(InputRecord.java:350)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:809)
at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:766)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:94)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:69)
at java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2265)
at java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:2558)
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2568)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1314)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:368)
so why the Connection Timed out exceptions are thrown?
This problem is solved. using the tcpdump to capture the messages flows. I have found that while in the application level, ObjectOutputStream.writeObject() method was invoked, in the tcp level, many times [TCP ReTransmission] were found.
So, I concluded that the connection is possibly be dead, although using the netstat -an command the tcp connection state still was ESTABLISHED.
So I wrote a testing application to periodically sent Testing messages as the heart-beating messages from the Server. Then this problem disappeared.
The read() methods of java.io.InputStream are blocking calls., which means they wait "forever" if they are called when there is no data in the stream to read.
This is completely expected behaviour and as per the published contract in javadoc if the server does not respond.
If you want a non-blocking read, use the java.nio.* classes.

SocketException Connection Reset

I created a server which accept TCP connection . After connected to socket it looping for reading data from input stream.
Steps:
I started my server.
Start Client.
Now I am closing client.
Then Server gives me SocketException Connection Reset
How do I check that my client is alive or not before reading from input stream.
If your server gets a 'connection reset' it is probably writing to a connection that has already been closed by the other end. A browser whose user presses the 'back' button is a good example. If this is an expected condition, ignore the exception. If it constitutes an application protocol error, debug the application.
There are 2 ways you can check if a socket is connected, you can either read or write to it, if it is connected you wont get an error, if it isnt connected you will get an error. This is how i check if a socket is connected:
BufferedReader reader;
public void run()
{
try
{
String message;
while((message = reader.readLine())!=null) //The thread stops here untill the reader has somthing to read
{
System.out.println(message);
}
}catch(Exception e)
{
System.out.println("Client disconnected!");
// an error is thrown when reader cannot read the stream because it is closed, you will get a connection reset error.
}
}
When the Socket is connected the reader waits untill there is somthing to be read(message = reader.readLine()). When the client disconnects and the Socket is closed, the reader throws an exception because there is nothing that can be read because the stream is closed. I hope this helps!

Categories

Resources