outputStream shutdown causes the other Streams blocks? - java

I have a server with many clients.. Every connection arrives to the server
if it's accepted, I send it to a thread:
server= serverSocketcht.accept();
new ThrdConv(server).start();
in the ThrdConv thread I set the input stream and output stream to this new conection
this.OOS=new ObjectOutputStream(server.getOutputStream());
this.OIS=new ObjectInputStream(server.getInputStream());
then I store the arrived connection, (lets call it new client) in a list of clients:
if(isLogged){ // if success login!
thsisUser= new Clientuser(server,OOS,OIS,Omsg.my_gender,Omsg.userID);
boolean IsAdded= EIQserver.OnlineusersList.add(this.thsisUser);
everything works fine and the Clients can send messages and chat with other clients...
The problem is when a client leaves, I get this Exception :
SEVERE: null
java.io.EOFException
at
java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2571)
here is my Leave function:
Iterator<Clientuser> iterator = EIQserver.OnlineusersList.iterator();
if(EIQserver.OnlineusersList.size()>=1)
Omsg.type= MessageType.Leave;
sendMessage(OLeavemsg); // tell the partner that I am leaving...
while (iterator.hasNext()) {
Clientuser next = iterator.next();
if (next.ID.equals(OLeavemsg.userID))
{
next.ClientPort.shutdownInput(); // ClientPort is a socket of this Client
next.ClientPort.shutdownOutput();
iterator.remove();// remove the partner
}
break;
}
// end leave////////////////////////////////////////////////
The connection is removed from the list, but the above exception stops the Server...
help me get rid of this complex problem

You should close this.OOS and this.OIS. They will close inner streams recursively. in you current case outer streams fail because client is closed first. You can examine Object*Stream, their close method close inner stream too.

thank you Mikhail, your answer was the key of the solution.
And for the other readers,I will Describe how did I solve this:
first I closed the OOS,OIS... as you advice..
secondly I stop the thread..
How do I stop the thread? :
I declared new boolean variable named "Running" and set the condition for the main loop of the thread to while(running)
and when I want to stop the main loop of the thread I set running=false
this stop the the use of the closed streams!!

You shutdown the input, you got EOFException when reading the input. That's exactly what's supposed to happen. You have to catch EOFException anyway when reading an ObjectInputStream. There is no 'complex problem' here at all. Just poor exception handling.

Related

Socket connection half dropped - IOException not thrown

i read some of the answers here about this problem, but i wasn't satisfied with them, so i decided to ask it my self. So I know that there are similar questions, but since the answers don't really work for me, i asked myself.
I have an app that lets 2 users connect to each other (one works as a server, the other one as client). They will send files through that socket connection. I am using a Service with 2 threads inside, one to read, another one to send the file that the user chose.
Here is the problem : If a client closes the app by swiping it on the android menu (of the apps that are running), and then the server (the other guy) tries to send him something, in my opinion it should throw an IOException, since the other end of the socket streams is over. But it is not doing that and i don't know why. If i try to send something to someone that left, i want to show a Toast.
Edit: just noticed it always stops at the instruction out.reset();
Do any of you know why that exception is not being thrown?
What could be a possible solution.
PS: It is a lite app, so to send Keep Alive messages wouldn't be a good solution. Also, it already showed the toast that i have one or two times, but then i couldn't replicate that behaviour again.
Here is my code where i wan't that to happen :
ClientHandler tmp = connectedClients.get(key);
ObjectOutputStream out = tmp.getOut();
Socket s = tmp.getSocket();
if(s.isClosed()){
System.out.println("The socket of this client "+key + " is closed!");
}
if(s.isOutputShutdown()){
System.out.println("The output of this client is shutdown !");//only checks this side, the other one is the one that is shutdown
}
System.out.println("changed the culpado to : "+1);
createSendNotification();
File apkToSend;
for(int i=0;i<listOfApps.size();i++){
System.out.println("Item do be sent is : "+i);
HighwayGridViewAppItem tmpItem=listOfApps.get(i);
filePath=tmpItem.getFilePath();
appName=tmpItem.getAppName();
System.out.println("his filepath to send is : "+filePath);
System.out.println("his appname to send is : "+appName);
couldSend=false;
apkToSend=new File(filePath);
if(apkToSend.exists()){//do i reallly need this if?
apkToSendSize=apkToSend.length();
System.out.println("File size: " +apkToSendSize);
try{
out.writeObject(appName +": "+ apkToSendSize);//appName to send to have the name of the file
byte[] buffer = new byte [8192];
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend));
int count;
totalToSend =0;
showSendProgress();
while((count=bis.read(buffer))!=-1){
out.write(buffer,0,count);
totalToSend +=count;
out.reset();
System.out.println("ServerComm send thread - already sent this ammount : "+ totalToSend);
}
out.flush();
bis.close();
}
catch ( IOException e){
System.out.println("It is throwing the input output exception");
e.printStackTrace();
connectedClients.remove(key);
if(clients.size()<=1){
h.post(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "No one is in your group.", Toast.LENGTH_SHORT).show();
}
});
i=listOfApps.size()+1;
}else{
System.out.println("Has more than one");
}
}
PS: When i try to send to a "closed" client, it prints a few "ServerComm send thread - already sent this ammount : "+ totalToSend" but then just stops, which is when i think it should throw the exception, but it just stops, and doesn't give any error, the app continues its life, but i NEED to give some input to the user that some problem went down.
Also, I create that Handler in the onCreate method of this service, it is being correctly created (since it is in a Service, it needs different creation) with the main looper.
Thank you guys in advance.
EDIT: Eventually, after almost 4 minutes, it throws a SocketException, but i can't wait that long.
Just because Android disposes of an app does not mean that internally all of your open connections are closed, it is mostly likely you need to detect the Android event and then execute the code that explicitly closes the open socket rather than waiting for Android to take care of it eventually. Otherwise, you will have to wait for the socket to be closed by garbage collection calling the finalizer.
This post here has some details about Android events and the onDestroy method in particular: How to close Android application?
If you require an immediate disconnection detection then you would have to implement your own ping/keep alive mechanism which would normally mean sending packets and acknowledging them continuously to be able to catch an exception more reliably.

While true loop being broken by a try/catch in Java

I am a beginner to networking and am working on implementing it in a game i have, it is mostly working but in the client my loop receiving packets is stopping ant a try catch. here is the code:
public void run() {
while(true){
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
}catch(IOException e){
e.printStackTrace();
}
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
}
}
After debugging i have found that the loop is not getting past the try catch statement.(but the try is being activated once seemingly with no error).
First of all your loop condition that you provided is not a variable, You have directly used a boolean valued true . It might a situation of infinite-loop.
while(true){..... // yourCode ....}
Your loop will continue even if socket.receive(packet); line raise an IOException because this exception is handled by the catch() block.
it means it will execute till any exception raised at this line
this.parsePacket(packet.getData(), packet.getAddress(), packet.getPort());
Now, Your problem is this method public void receive(DatagramPacket p) actually method will work till datagram is received but your loop will continue till exception is raised till this.parsePacket() method raised an Exception.
So, please change your conditional statement such that if datagram is no more present then loop must be terminated.
As per java-docs for the method public void receive(DatagramPacket p)
This method blocks until a datagram is received.
The thread executing the flow gets blocked [waits until the datagram is received]. Your loop is not broken its just in halt state.
Loop will be broken in case of some exception occurs which is not caught and handled in side the body of the loop.
Also there is little suggestion I would like you to implement in your code. You should not run an infinite loop. Instead of using true you can try using Thread.currentThread().isInterrupted() and when your game ends you can call interrupt() on the Thread responsible for executing the code flow of the loop. Also if in case of IOException you wish to retry (may be in retry resources are in order and you do not get the exception) then putting catch inside the loop is O.K. else you can move the catch outside the loop, it depends on your need and flow. You can probably put a counter for number of retries.

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.

Java - readObject() and setSoTimeout()

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.

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.

Categories