I am in the process of developing a game and I have a question.
I have a client where a user can log in to the game or disconnect using a unique account stored on a database.
How do I properly close a server on log out and re open on log in? Or should I never close the socket? The same question goes for DataInputStream and DataOutputStream.
I keep getting connection reset client sided, so I don't know what the best way to handle logging in/logging out within the same client runtime.
Thanks. :)
Just close the socket. That will terminate the corresponding thread at the server. One login should equal one socket.
You should do that by closing the outermost stream or Writer wrapped around the socket output stream. That flushes it and closes the other streams and the socket. Closing the input stream and the socket before this is incorrect, and doing so afterwards is redundant, but if you must do it it must be done after, not before, otherwise again you miss a flush.
Related
I'm writing a simple Java server that accepts multiple client socket connections. I'm using a separate thread to handle each client/socket. Considering I have set up the networking including the BufferedReader, InputStreamReader, and FileWriter etc. for this client/socket.
My code is :
//run method of my Runnable everytime a new client connects
public void run(){
String message = null;
while((message = bufferedReader.readLine())!=null){
System.out.println(message+"/n");
//do some other things like writing this message
//to another client or saving it in a file, etc
}
}
Does this keep the client socket open? or does the socket eventually makes the thread goes dead when it's done reading from the stream
Will it keep waiting for more/new messages/data from the client socket even after it's done reading for the first time?
Once the server accept client request, the server is capable of exchanging messages with the client endlessly until the socket is closed with its streams.
To allow continuity in communication, you have to read from the stream inside a while loop and only exit when the client sends a termination request. So in your case the client socket is open until you read, once you exit from the loop your connection will be terminated.
Where did you create the bufferedReader ?
The thread will end when the readLine call returns null. That happens when the reader reaches the "end of stream". If the BufferedReader is wrapping an input stream associated with a socket, then "end of stream" will be triggered by the socket connection closing; e.g. because the remote client / server closed it.
There is no code shown here to close the BufferedReader. It will be closed if either something else calls close on it, or if the BufferedReader object becomes unreachable. In the latter case, the reader and the underlying socket stream and socket will eventually be closed when the GC finalizes the objects.
My question is does this keep the client socket open? Or does the socket and eventually the thread goes dead when it's done reading from the stream, or will it keep waiting for more/new messages/data from the client socket even after it's done reading for the first time?
It depends. See above.
The point is that the code as written reads until there is no more to read. Not until "it is done". Or to put it another way "it is done" ... if and only if the other end tells it so, by closing the stream.
My SocketServer first listens for at least 4 Socket connections before creating a WorkerThread where all four connections are served. And in the same thread, all 4 sockets will be opened to perform communication with connected clients.
Now, consider a situation where server has already accepted two socket connections, but listening to remaining 2 clients, before it can proceed with creating thread.
And while that listening phase, the connected clients are shown "Waiting..." message (since server has not yet opened the sockets to send any response back to clients, and socket.readObject() is blocking at client-end), till the server gets all 4 clients to work with. And in the meantime, one of the "already-connected" client kills that "Waiting..." thing, and closes the client app. In such a case, my WorkerThread will fire an exception due to dead socket supplied, when it attempts to open it.
How can I know if a socket is pointing to nothing (since client is lost) without having to open the socket? (since if I open it from main thread, I'll not be able to open it again from WorkerThread, where it is actually supposed to be used).
If I get to know if Socket is dead, I can get server back to listening and attempt to get 4 connections, before it proceeds creating a thread.
I know my SocketServer will be stuck at accept() so even if its possible to check what I asked above, I'll have to create another thread that monitors liveliness of already "accepted" socket connections.
Update
I mean by not opening the socket is something like below.
Socket s = ss.accept();
/* I'll not be doing as below, since once I close InputStream and OutputStream in main Thread, I can't open in WorkerThread.
But I still want to know if Socket s is connected to client, before I start WorkerThread.
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
String msg = in.readObject().toString();
System.out.println("Client Says:");
out.writeObject("success");
in.close();
out.close();
*/
new WorkerThread(s).start();
And note that my server is accepting 4 such connections, and when 4 sockets are accept()ed, it passes all 4 in WorkerThread's constructor, and gets back to accept() another 4 clients.
I think you just need to handle your acceptions better. You should handle the IOException correctly whenever you try to read or write to the socket.
One option is to have the accepting code send a "still waiting" message to the client and get an acknowledge every so often while you are waiting for the other connections. The socket and associated streams have already been created by the accept() so you can do this, call flush() on the OutputStream, and then hand off to the handler.
As long as you don't call close() on the streams, you should be able to re-use them without a problem. You just can't have two different threads using the streams at the same time.
My client/server application currently keeps opening and closing new connections every time it wants to send/receive data. I'm trying to change it so it will have one persistent connection.
The problem I'm having is the socket's DataInputStream on the server keeps throwing EOFException's when I just want it to block until it receives the next batch of data.
I thought about just simply writing the server like this...
while socket is open {
while at socket's DataInputStream's EOF {
wait a second
}
//If we're here, then we have some data
do stuff
}
... but this is extremely ugly and not the proper way to block until some data is received.
Is there a cleaner way to tell the socket to block until there's some data to read? I've tried read() and readFully(), but neither work.
If you are getting EOFException, it means the connection is gone. You cannot wait on a connection that's closed. Keep working on your client code so that it doesn't close the connection. On the server side, any of the read methods will block until data is available without further effort from you.
I have a socket tcp connection between two java applications. When one side closes the socket the other side remains open. but I want it to be closed. And also I can't wait on it to see whether it is available or not and after that close it. I want some way to close it completely from one side.
What can I do?
TCP doesn't work like this. The OS won't release the resources, namely the file descriptor and thus the port, until the application explicitly closes the socket or dies, even if the TCP stack knows that the other side closed it. There's no callback from kernel to user application on receipt of the FIN from the peer. The OS acknowledges it to the other side but waits for the application to call close() before sending its FIN packet. Take a look at the TCP state transition diagram - you are in the passive close box.
One way to detect a situation like this without dedicating a thread to each socket is to use the select/poll/epoll/kqueue family of functions. The socket being passively closed will be signaled as readable and read attempt will return the EOF.
Hope this helps.
Both sides have to read from the connection, so they can detect when the peer has closed. When read returns -1 it will mean the other end closed the connection and that's your clue to close your end.
If you are still reading from your socket, then you will detect the -1 when it closes.
If you are no longer reading from your socket, go ahead and close it.
If it's neither of these, you are probably having a thread wait on an event. This is NOT the way you want to handle thousands of ports! Java will start to get pukey at around 3000 threads in windows--much less in Linux (I don't know why).
Make sure you are using NIO. Use a single thread to manage all your ports (connection pool). It should just grab the data from a thread, forward it to a queue. At that point I think I'd have a thread pool take the data out of the queues and process it because actually processing the data from a port will take some time.
Attaching a thread to each port will NOT work, and is the biggest reason NIO was needed.
Also, having some kind of a "Close" message as part of your stream to trigger closing the port may make things work faster--but you'll still need to handle the -1 to cover the case of broken streams
The usual solution is to let the other side know you are going to close the connection, before actually closing it. For instance, in the case of the SMTP protocol, the server will send '221 Bye' before it closes the connection.
You probably want to have a connection pool.
I have an application that uses simple sockets to pass some characters between two systems. I have my java application running as a server. I establish a connection fine, and even pass one message. However, after one message has been sent my connection closes.
From what I can tell it appears as if on closing the printWriter and bufferedReader the socket itself is being closed?! This is bad, as I have multiple messages to send on the same connection.
printWriter = new PrintWriter(theServer.getClientSocket().getOutputStream());
bufferedReader = new BufferedReader(new InputStreamReader(theServer.getClientSocket().getInputStream()));
printWriter.println("the line");
printWriter.close(); //Closing on these lines?
bufferedReader.close(); //Closing on these lines?
Am I full of it? How do I maintain this connection in Java?
Yes, closing any Writer/Reader will close all other Writers and Readers that they wrap. Don't close it until you are ready to close the underlying socket.
As #Eddie said (seconds before me! :) ), closing the writer and/or the reader will close the underlying socket streams and the socket itself: However, I believe the socket itself will not be closed.
Closing the returned InputStream will close the associated socket.
You shouldn't close the writer nor the reader. Just flush the writer to make sure your messages will arrive in time. Closing the socket later on will close the respective streams, so you don't need to close them yourself. Just leave your reader/writer objects to the GC.
Another alternative is to create yourself a NoCloseInputStream and NoCloseOutputStream filters which simply do nothing on close; then use them to wrap your application socket's streams (before any application wrappering like a buffer).
Note that if you were to do this, you would need to keep a reference to the socket (or the wrapped streams) so that you can close the socket when you are actually done with it.
To answer the comment that this is "too advanced a concept for the OP": The OP's problem is that in closing the top level stream, he is also closing the underlying socket, but that's no good since he wants to create further top-level streams over the socket to send further messages. Depending on his architecture, the only way to achieve this may be to wrap the streams in NoClose wrappers - for example he may be passing the streams to an XML serializer or deserializer which closes the stream when it's done, which close is outside of his control.
You need to close the socket after closing the streams.