I am writing a simple client/server chat program. The server handles multiple clients in this way:
public void start(int port)
{
(new Thread(new Runnable()
{
#Override
public void run() {
try{
serverSocket = new ServerSocket(port);
SocketHandler handler;
while(true)
{
handler = new SocketHandler(serverSocket.accept());
handlersList.add(handler);
(new Thread(new SocketHandler(socket))).start();
}
}catch(IOException e)
{
for(SocketHandler handler:handlersList)
handler.close();
}
}
})).start();
}
public void stop() throws IOException
{
serverSocket.close();
}
Basically start() instantiates the ServerSocket and waits for clients to connect indefinitely. Whenever the user wants to close the server, the Server Socket is closed, which causes the accept() to fail and to throw and exception. Then the catch(){} closes the various sockets created. My questions are:
Do I have to close every socket created through serverSocket.accept()?
Is this the right way to stop such a server? That while(true) + use of exceptions for non-exceptional circumstances feels so wrong to me. Is there a better way?
Could I use an ExecutorService and then just call shutdownNow on it? Will the shutdownNow be able to stop the accept() call? Because the api doc states that it is not guaranteed to succeed.
Please, feel free to point out any error/poor design choice that I've made. Ty
You can either close you connections manually (both client/server side) using the close() method or you can set a timeout.
Set a timeout on blocking Socket operations:
ServerSocket.accept();
SocketInputStream.read();
DatagramSocket.receive();
The option must be set prior to entering a blocking operation to take
effect. If the timeout expires and the operation would continue to
block, java.io.InterruptedIOException is raised. The Socket is not
closed in this case.
Is this the right way to stop such a server?
As you say it is a server that means you should not need to stop it but in exceptional conditions.
As you state the shutdownNow() API says:
There are no guarantees beyond best-effort attempts to stop processing
actively executing tasks.
Related
Explanation
I'm revisiting the project I used to teach myself Java.
In this project I want to be able to stop the server from accepting new clients and then perform a few 'cleanup' operations before exiting the JVM.
In that project I used the following style for a client accept/handle loop:
//Exit loop by changing running to false and waiting up to 2 seconds
ServerSocket serverSocket = new ServerSocket(123);
serverSocket.setSoTimeout(2000);
Socket client;
while (running){ // 'running' is a private static boolean
try{
client = serverSocket.accept();
createComms(client); //Handles Connection in New Thread
} catch (IOException ex){
//Do Nothing
}
}
In this approach a SocketTimeoutException will be thrown every 2 seconds, if there are no clients connecting, and I don't like relying on exceptions for normal operation unless it's necessary.
I've been experimenting with the following style to try and minimise relying on Exceptions for normal operation:
//Exit loop by calling serverSocket.close()
ServerSocket serverSocket = new ServerSocket(123);
Socket client;
try{
while ((client = serverSocket.accept()) != null){
createComms(client); //Handles Connection in New Thread
}
} catch (IOException ex){
//Do Nothing
}
In this case my intention is that an Exception will only be thrown when I call serverSocket.close() or if something goes wrong.
Question
Is there any significant difference in the two approaches, or are they both viable solutions?
I'm totally self-taught so I have no idea if I've re-invented the wheel for no reason or if I've come up something good.
I've been lurking on SO for a while, this is the first time I've not been able to find what I need already.
Please feel free to suggest completely different approaches =3
The problem with second approach is that the server will die if an exception occurs in the while loop.
The first approach is better, though you might want to add logging exceptions using Log4j.
while (running){
try{
client = serverSocket.accept();
createComms(client);
} catch (IOException ex){
// Log errors
LOG.warn(ex,ex);
}
}
Non-blocking IO is what you're looking for. Instead of blocking until a SocketChannel (non-blocking alternative to Socket) is returned, it'll return null if there is currently no connection to accept.
This will allow you to remove the timeout, since nothing will be blocking.
You could also register a Selector, which informs you when there is a connection to accept or when there is data to read. I have a small example of that here, as well as a non-blocking ServerSocket that doesnt use a selector
EDIT: In case something goes wrong with my link, here is the example of non-blocking IO, without a selector, accepting a connection:
class Server {
public static void main(String[] args) throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
while(true) {
SocketChannel sc = ssc.accept();
if(sc != null) {
//handle channel
}
}
}
}
The second approach is better (for the reasons you mentioned: relying on exceptions in normal program flow is not a good practise) allthough your code suggests that serverSocket.accept() can return null, which it can not. The method can throw all kinds of exceptions though (see the api-docs). You might want to catch those exceptions: a server should not go down without a very good reason.
I have been using the second approach with good success, but added some more code to make it more stable/reliable: see my take on it here (unit tests here). One of the 'cleanup' tasks to consider is to give some time to the threads that are handling the client communications so that these threads can finish or properly inform the client the connection will be closed. This prevents situations where the client is not sure if the server completed an important task before the connection was suddenly lost/closed.
I have a simple ServerSocket-based java program which accepts a client connection and puts it in a threadpool (ThreadPoolExecutor):
while() {
socket = serverSocket.accept();
pool.submit(new Client(socket)); // Client is a Runnable
}
Problem is when I try to shutdown the program and client threads stay around until the connection is closed on the other end (the jvm does not exit until then).
I could try to maintain all client objects and close all their sockets when server is about to shutdown. But I have no clue how maintain them? Especially removing them when done.
I tried beforeExecute etc, but that only gives me another object (a FutureTask), not the Client object I'm looking for.
Update:
The problem is not adding sockets to a list, the problem is removing them when they are done as there are no way (afaik) to use afterExecute for that.
Store all the sockets in a List before submitting them to the pool. Then the shutdown thread can call close() on all the sockets, which should cause the blocked threads to throw SocketExceptions.
One way is to to have the Client return itself (in the Future) when done. Just need a list and then use the afterExecute method.
Like this:
pool =new ThreadPoolExecutor(...) {
#Override
protected void afterExecute(Runnable r, Throwable t) {
// The future returns the Client object!
client = (Client)((FutureTask)r).get();
// Remove it from list of known clients
clients.remove(client);
}
};
while() {
socket = serverSocket.accept();
Client client = new Client(socket)
// Submit to pool, using client as the future return value
pool.submit(client, client);
// Add to list of known clients
clients.add(client);
}
// When app is closing
private shutdown() {
for(Client client : clients){
client.shutdown();
}
}
Call shutdownInput() on all the client sockets. That will cause the associated threads to think that the peer has disconnected and so exit gracefully.
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?
This question has no doubt been asked in various forms in the past, but not so much for a specific scenario.
What is the most correct way to stop a Thread that is blocking while waiting to receive a network message over UDP.
For example, say I have the following Thread:
public class ClientDiscoveryEngine extends Thread {
private final int PORT;
public ClientDiscoveryEngine(final int portNumber) {
PORT = portNumber;
}
#Override
public void run() {
try {
socket = new DatagramSocket(RECEIVE_PORT);
while (true) {
final byte[] data = new byte[256];
final DatagramPacket packet = new DatagramPacket(data, data.length);
socket.receive(packet);
}
} catch (SocketException e) {
// do stuff 1
} catch (IOException e) {
// do stuff 2
}
}
}
Now, would the more correct way be using the interrupt() method? For example adding the following method:
#Override
public void interrupt() {
super.interrupt();
// flip some state?
}
My only concern is, is socket.receive() not a non-interruptable blocking method? The one way that I have thought of would be to implement the interrupt method as above, in that method call socket.close() and then cater for it in the run method in the catch for the SocketException. Or maybe instead of while(true) use some state that gets flipped in the interrupt method. Is this the best way? Or is there a more elegant way?
Thanks
The receive method doesn't seem to be interruptible. You could close the socket: the javadoc says:
Any thread currently blocked in receive(java.net.DatagramPacket) upon
this socket will throw a SocketException
You could also use setSoTimeout to make the receive method block only for a small amount of time. After the method has returned, your thread can check if it has been interrupted, and retry to receive again for this small amount of time.
Read this answer Interrupting a thread that waits on a blocking action?
To stop a thread, you should not user neither interrupt nor stop in java. The best way, as you suggested by the end of your question, is to have the loop inside the main method controlled by a flag that you can rise as needed.
Here is an old link about this :
http://download.oracle.com/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html
Other ways of stopping a thread are deprecated and don't provide as much control as this one. Also, this may have changed a bit with executor services, I didn't have time to learn much about it yet.
Also, if you want to avoid your thread to be blocked in some IO state, waiting for a socket, you should give your socket a connection and reading time out (method setSoTimeout).
Regards,
Stéphane
This is one of the easier ones. If it's blocked on a UDP socket, send the socket a UDP message that instructs the receiving thread to 'stop'.
Rgds,
Martin
I have a server thread with this code:
public void run() {
try {
ServerSocket server;
EneaLog.printLog("Server is running.");
server = new ServerSocket(this.portnumber);
while (true) {
new EneaServerConnection(server.accept(), this.project,stopped).start();
if (stopped) {
EneaLog.printLog("Server safe-shutdown completed.");
EneaLog.printLog("Hi!");
server.close();
return;
}
}
} catch (IOException ex) {
Logger.getLogger(EneaServer.class.getName()).log(Level.SEVERE, null, ex);
project.getExceptionHandler().handler(ex);
}
}
and a shutdown method like this:
public void shutdown() {
EneaLog.printLog("Server shutdown NOW!");
stopped = true;
}
I want that shutdown can unblock thread that are waiting on server.accept() otherwise I must wait for connection before server shutdown.
I can't do server.close() in shutdown() because I must signal to registered client that server is coming down.
Any ideas?
I try to design my code so that it can be "shutdown" with an interrupt. Mainly, this is because the Executor framework in Java's concurrency package uses interrupt to cancel running tasks. Also, the "shutdown" task doesn't have to know any internals of the task being killed.
However, a call to accept will not respond to an interrupt unless it is created from a ServerSocketChannel. A server created with a ServerSocket constructor will ignore interrupts, and I haven't found a way to reconfigure this.
If you can't change the code that creates the server, arrange for another thread to call close on the server socket. This will also raise an exception in thread blocked on accept, regardless of the method used to create the server socket.
This turns out to be a really big pain when using SSL. A JSSE socket is not created from an InterruptibleChannel, and won't respond to a simple interrupt on the thread.
I just noticed that the question says that the server can't be closed without notifying the client. Successfully interrupting a socket results in its closure.
On a call to accept this shouldn't be a problem, since the client is not connected if the server socket is blocked in accept. That should only be an issue for Socket instances, that represent current connections.
If that doesn't satisfy the notification requirements, a rework to use NIO's ServerSocketChannel in non-blocking mode may be necessary.
You should be able to close the socket from another thread.
Neither interrupt (that's dependent on interrupt points in the same way cancellation is dependent on cancellation points) nor close will do it (accept does not responsed to closing its file descriptor). You'll have to communicate with the accept (try sendto, with a shutdown notification) to notify it to not continue accepting. At least this is the case on linux; don't know what it's like on other platforms.
I've been faced to the same problem. My working solutions consists into closing the ServerSocket object (serverSocket.close()) ; doing this will cause the accept() method to throw a SocketException, which is what you want to do.
Vincent
Have you tried Thread.interrupt() ?
If this thread is blocked in an I/O
operation upon an interruptible
channel then the channel will be
closed, the thread's interrupt status
will be set, and the thread will
receive a ClosedByInterruptException.
If this thread is blocked in a
Selector then the thread's interrupt
status will be set and it will return
immediately from the selection
operation, possibly with a non-zero
value, just as if the selector's
wakeup method were invoked.