Java - readObject() and setSoTimeout() - java

So, i wrote a thread on my client side , which tries to readObject() from a socket stream.
This thread runs as long the client is connected.
The connection to the server can be closed on the client's GUI.
If the client decides to disconnect(this will not exit the client program) by clicking the
"disconnect" menu option, the socket will be closed and a isConnected is set to false.
Since the clients read thread tries to readObject() from stream, while the connection can be closed via the GUI, i set a timeout to 250ms (setSoTimeout(250)).
#Override
public void run()
{
this.connection = this.connectionHandler.getSocket();
while(connectionHandler.isConnected())
{
this.readCircle();
}
this.connectionHandler.setReadTaskRunning(false);
}
private void readCircle()
{
try
{
this.connection.setSoTimeout(250);
this.connectionHandler.readData(); //this uses readObject().
}
catch(SocketTimeoutException timeout){}
catch(...){}
}
I know that readObject() will block, and to check if the client is still connected, i wraped it in a while, which checks (every timeout) if the client socket is still connected.
My question now:
In case, if the readObject() starts to get a object passed by the server, tries to read it, but while processing a timeout occurs, will the data on the stream be "damaged" in some way, because it canceled.
Or should i just let the readObject() block and catch a exception if the GUI thread wants to close the socket.
I'm not very experienced with sockets and maybe my approach is wrong at all.

Socket read timeout will cause a SocketTimeoutException to be thrown by readObject(). You may not be able to reuse that ObjectInputStream, and the stream may be damaged because its current position will stay largely undefined.
This probably can only be fixed by closing and reopening the connection.

Related

java socket - handling client disconnection [duplicate]

I am running into some issues with the Java socket API. I am trying to display the number of players currently connected to my game. It is easy to determine when a player has connected. However, it seems unnecessarily difficult to determine when a player has disconnected using the socket API.
Calling isConnected() on a socket that has been disconnected remotely always seems to return true. Similarly, calling isClosed() on a socket that has been closed remotely always seems to return false. I have read that to actually determine whether or not a socket has been closed, data must be written to the output stream and an exception must be caught. This seems like a really unclean way to handle this situation. We would just constantly have to spam a garbage message over the network to ever know when a socket had closed.
Is there any other solution?
There is no TCP API that will tell you the current state of the connection. isConnected() and isClosed() tell you the current state of your socket. Not the same thing.
isConnected() tells you whether you have connected this socket. You have, so it returns true.
isClosed() tells you whether you have closed this socket. Until you have, it returns false.
If the peer has closed the connection in an orderly way
read() returns -1
readLine() returns null
readXXX() throws EOFException for any other XXX.
A write will throw an IOException: 'connection reset by peer', eventually, subject to buffering delays.
If the connection has dropped for any other reason, a write will throw an IOException, eventually, as above, and a read may do the same thing.
If the peer is still connected but not using the connection, a read timeout can be used.
Contrary to what you may read elsewhere, ClosedChannelException doesn't tell you this. [Neither does SocketException: socket closed.] It only tells you that you closed the channel, and then continued to use it. In other words, a programming error on your part. It does not indicate a closed connection.
As a result of some experiments with Java 7 on Windows XP it also appears that if:
you're selecting on OP_READ
select() returns a value of greater than zero
the associated SelectionKey is already invalid (key.isValid() == false)
it means the peer has reset the connection. However this may be peculiar to either the JRE version or platform.
It is general practice in various messaging protocols to keep heartbeating each other (keep sending ping packets) the packet does not need to be very large. The probing mechanism will allow you to detect the disconnected client even before TCP figures it out in general (TCP timeout is far higher) Send a probe and wait for say 5 seconds for a reply, if you do not see reply for say 2-3 subsequent probes, your player is disconnected.
Also, related question
I see the other answer just posted, but I think you are interactive with clients playing your game, so I may pose another approach (while BufferedReader is definitely valid in some cases).
If you wanted to... you could delegate the "registration" responsibility to the client. I.e. you would have a collection of connected users with a timestamp on the last message received from each... if a client times out, you would force a re-registration of the client, but that leads to the quote and idea below.
I have read that to actually determine whether or not a socket has
been closed data must be written to the output stream and an exception
must be caught. This seems like a really unclean way to handle this
situation.
If your Java code did not close/disconnect the Socket, then how else would you be notified that the remote host closed your connection? Ultimately, your try/catch is doing roughly the same thing that a poller listening for events on the ACTUAL socket would be doing. Consider the following:
your local system could close your socket without notifying you... that is just the implementation of Socket (i.e. it doesn't poll the hardware/driver/firmware/whatever for state change).
new Socket(Proxy p)... there are multiple parties (6 endpoints really) that could be closing the connection on you...
I think one of the features of the abstracted languages is that you are abstracted from the minutia. Think of the using keyword in C# (try/finally) for SqlConnection s or whatever... it's just the cost of doing business... I think that try/catch/finally is the accepted and necesary pattern for Socket use.
I faced similar problem. In my case client must send data periodically. I hope you have same requirement. Then I set SO_TIMEOUT socket.setSoTimeout(1000 * 60 * 5); which is throw java.net.SocketTimeoutException when specified time is expired. Then I can detect dead client easily.
I think this is nature of tcp connections, in that standards it takes about 6 minutes of silence in transmission before we conclude that out connection is gone!
So I don`t think you can find an exact solution for this problem. Maybe the better way is to write some handy code to guess when server should suppose a user connection is closed.
As #user207421 say there is no way to know the current state of the connection because of the TCP/IP Protocol Architecture Model. So the server has to notice you before closing the connection or you check it by yourself.
This is a simple example that shows how to know the socket is closed by the server:
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null)
log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");
Here you are another general solution for any data type.
int offset = 0;
byte[] buffer = new byte[8192];
try {
do {
int b = inputStream.read();
if (b == -1)
break;
buffer[offset++] = (byte) b;
//check offset with buffer length and reallocate array if needed
} while (inputStream.available() > 0);
} catch (SocketException e) {
//connection was lost
}
//process buffer
Thats how I handle it
while(true) {
if((receiveMessage = receiveRead.readLine()) != null ) {
System.out.println("first message same :"+receiveMessage);
System.out.println(receiveMessage);
}
else if(receiveRead.readLine()==null)
{
System.out.println("Client has disconected: "+sock.isClosed());
System.exit(1);
} }
if the result.code == null
On Linux when write()ing into a socket which the other side, unknown to you, closed will provoke a SIGPIPE signal/exception however you want to call it. However if you don't want to be caught out by the SIGPIPE you can use send() with the flag MSG_NOSIGNAL. The send() call will return with -1 and in this case you can check errno which will tell you that you tried to write a broken pipe (in this case a socket) with the value EPIPE which according to errno.h is equivalent to 32. As a reaction to the EPIPE you could double back and try to reopen the socket and try to send your information again.

Socket isClosed() returns false after client disconnected [duplicate]

This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
In my java application, I have a TCP server which sends data generated in my app to all connected clients. For each new socket, I create a new thread. Following is the thread code.
public void run() {
try {
PrintStream printStream = new PrintStream(socket.getOutputStream(), true);
while (true) {
if (socket.isClosed()) {
break;
}
synchronized (DataSource.getInstance()) {
printStream.println(DataSource.getInstance().getData());
try {
DataSource.getInstance().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Data generating thread writes to DataSoure when new data is available and calls notifyAll() so all threads which handles connected sockets wake up and send available data to clients.
My problem is, even if a client disconnected, socket.isClosed() returns true. So the thread which handles the socket never gets terminated.
Why does this happen? How can I exit the thread when a client gets disconnected?
There is no "disconnect" with TCP. A peer can only indicate that it does not want to send anything more (send FIN) but this does not mean that it does not want to receive anything. The other end only realizes that read is unwanted too once it tries it and gets a RST back.
If you take the "don't want to read" as an indicator that the client closed (you might if the application protocol is this way) then you can test if the peer "disconnected" by simply reading from the socket. The system call then returns no error but 0 bytes and this means that there will be no more data from the peer. In Java this case gets translated into an EOFException.
Apart from that a socket does not get closed automatically - only explicitly. isClosed only returns true once the socket is explicitly closed on your local end, not the peer's end. And isConnected will also not tell you if the other end "disconnected", it will only tell you if your end did connect to the peer.
See also Java Socket API: How to tell if a connection has been closed?.
You should use isConnected() function instead of isClosed() in order to detect if the remote socket is closed.

Detect a server side FIN packet

I'm got the following Java code:
Socket s = new Socket();
s.connect(mySockAddr, myTimeout);
Assuming I don't use the socket, I need to detect a server side connection close (FIN or RST packet) as soon as it happens.
For instance, though a thread which checks socket status, or intercepting the FIN/RST packets...
How can I detect it?
I've tried with printWriter.checkError(), socket.isConnected(), socket.isClosed() methods but nothing works.
The only way i know of to detect whether the other side has closed the connection is by attempting to read from the input stream. A read from a shut-down socket will return -1. That's your notification that there won't be any more to read.
As far as the other functions go, s.isConnected() tells you whether you've successfully connect()ed the socket, and s.isClosed() would tell you whether you closed it. It tells you nothing about what the other side has done.

shutdown TCP thread server

I coded a little TCP thread Server, which creates a new thread for every server.accept(). Nearly everything works great, but I have problems to kill all threads per interrupt. (I use a ServiceExecutor to manage the threads. Therefore I use the shutdownNow method to reach the interrupt-methods) The Worker-instances use a BufferedReader and it's readline-method to receive and compute the input. AFAIK the readline blocks and would not react on an interrupt, but how to stop it?
while(!isInterrupted()){
try {
clientSocket = this.serverSocket.accept();
} catch(IOException e){
break;
}
this.threadPool.execute(new ThreadWorker(clientSocket));
}
threadPool.shutdownNow();
try{
serverSocket.close();
}catch(IOException e){
//todo
}
I tried to close the ServerSocket to kill the Input/Output Streams, but it didn't work as expected.
A couple alternatives:
1) If you are closing the whole app, and there is nothing of importance to explicitly close, call System.Exit(0). HEALTH WARNING - doing this causes some developers to have apoplectic fits and post endlessly about 'cleaning up gracefully'.
2) Keep a thread-safe list of all client sockets in the accept() thread. Pass a reference to this list as part of your client context that is passed to the client<>server threads. Add new connections to the list in the accept() thread. When a client thread detects a disconnect, remove its entry from the list. When you want to close all clients, iterate the list and close the client sockets - this will cause the readline method to return early, with an error, in the client threads.

How to interrupt a thread if it is to open socket?

I have tried to close the current thread that is a part of multi-threading server.
The thread is ready to open the socket that may be accessed by clients.
Everything works fine except when the code below is contained in while() loop.
new ServerThread(serversocket.accept(), this.Rstr,
bag.numberofDatatoAcquire).start();
Here is the code for the server:
public void run() {
System.out.println("This has been called ");
try{
System.out.println("This has been tried");
serversocket = new ServerSocket(this.iPort);
Thread thisThread = Thread.currentThread();
while(!thisThread.isInterrupted()){
new ServerThread(serversocket.accept(), this.Rstr, bag.numberofDatatoAcquire).start();
//sending socket accessed, where it will store the data and how much it will collect it.
System.out.println("This has been running");
Thread.sleep(10);
}
}catch(InterruptedException e){
//why bother? it is an usual happening...lol
}catch(IOException ioe)
{
System.err.println("Can't open the socket on port");
}
finally{
System.out.println("Thread is dead and ready for change");
}
}
And this is a part of GUI events: this works well without "new ServerThread..." code.
private OverWatch EW = new OverWatch(bag.iPortOrder, bag.SessionAcquisitionSavingDirectory);
....
private void OverWatcherControl(boolean checker)
{
if(checker)
EW.start();
else
EW.interrupt();
}
Since the variable bag.numberofDataToAcquire (public integer type) is supposed to be changed whenever user wants, I think I have to stop this thread and change the variable then run this thread again. Am I wrong? Or how can I interrupt this thread?
Thanks,
ServerSocket.accept() is a blocking call that is not responsive to thread interruption. Almost all the java.net blocking calls (connect, read, accept, etc) do not respond to Thread.interrupt(). This behavior is "as designed".
A way to wake up a thread blocked in .accept() or .read() is to close the underlying socket.
Alternatively you could set SO_TIMEOUT (setSoTimeout) on the ServerSocket, which will cause .accept() to wake up periodically by throwing a SocketTimeoutException. You could catch that exception and use it as an opportunity to check the interrupt status on the thread.
The java.nio package (Java 1.4+) provides an alternate sockets API that is more responsive to interruption.
Just as an alternative to using a timeout or killing the socket:
Fake a new connection to the socket. This will "wake up" the accept() and then an additional signaling mechanism (e.g. flag or interrupt check) can be used (although the logic would have to be altered slightly from shown to not "lie" in the println).
I have used this approach before and it worked well: no need to wait for a timeout (even a sort one) or handle another exception and the socket remains open/valid (which may or may not be desired). On the other hand, I'm not sure what would happen on a really long/broken TCP handshake, but that's a case I never encountered ;-)
Happy coding.
I initially answered it using the serverSocket.setSoTimeout(millis) and handling the SocketTimeoutException. See below.
A better way to do it would be to use ServerSocketChannel which gets interrupted in the accept() call when you call thread.interrupt() so you don't have to spin at all. So you'd do something like:
ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.socket().bind(new InetSocketAddress(this.iPort), 10);
...
while (! thisThread.isInterrupted()) {
// channel accepts _are_ interrupted by the call to thread.interrupt()
// it throws ClosedByInterruptException when interrupt() is called
SocketChannel accepted = socketChannel.accept();
new ServerThread(accepted.socket(), this.Rstr,
bag.numberofDatatoAcquire).start();
}
I'll take a whack at explaining the code:
while(!thisThread.isInterrupted()){
new ServerThread(serversocket.accept(), this.Rstr,
bag.numberofDatatoAcquire).start();
Thread.sleep(10);
}
I think your problem here is that serversocket.accept() hangs waiting for a socket to be accepted. From the accept() javadocs:
Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
You need to set a timeout on your socket before the while loop. You can use setSoTimeout(millis) for that.
serversocket.setSoTimeout(10000);
This will then throw a SocketTimeoutException if it times out. Then you won't need the Thread.sleep(10) (which is for 10ms btw) because the sleeping will be done inside of the accept() method. I would not recommend accept(10) because that would spin pretty aggressively.

Categories