Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gracefully terminating socket thread

Based on examples here, the simple socket server client will terminate when .bye is sent. The code below uses a thread-based approach to accept multiple clients but does not handle graceful handle client termination and will error out by repeating null.

The first example in the aforementioned link causes the client and server to exit. The server code below does not have a provision to disconnect when ".bye" is received. I would like the client to gracefully disconnect from the server. The server should close the connection when the ".bye" is received from the client. I believe this needs to be handled in the System.out.println(streamIn.readUTF()); in the ChatServerThread?

Question updated to reflect answer feedback, see history for original code:

import java.net.*;
import java.io.*;

public class ChatServerThread implements Runnable
//public class ChatServerThread extends Thread
{  private Socket          socket   = null;
   private ChatServer      server   = null;
   private int             ID       = -1;
   private DataInputStream streamIn =  null;
   private DataOutputStream streamOut = null;

   public ChatServerThread(ChatServer _server, Socket _socket)
   {  server = _server;  socket = _socket;  ID = socket.getPort();
   }
   public void run() {
   try {
       handleClient();
   } catch( EOFException eof ) {
        System.out.println("Client closed the connection.");
   } catch( IOException ioe ) {
        ioe.printStackTrace();
   }
}

   public void handleClient() throws IOException {
      boolean done = false;
      try {
      System.out.println("Server Thread " + ID + " running.");
      while (!done) {
        String nextCommand = streamIn.readUTF();
        if( nextCommand.equals(".bye") ) {
           done = true;
        } else {
           System.out.println( nextCommand );
        }
     }
   } finally {
     streamIn.close();
     streamOut.close();
     socket.close();
   }
   }
   public void open() throws IOException
   {
      streamIn = new DataInputStream(new BufferedInputStream(socket.getInputStre
am()));
      streamOut = new DataOutputStream(new BufferedOutputStream(socket.getOutput
Stream()));
   }
   public void close() throws IOException
   {  if (socket != null)    socket.close();
      if (streamIn != null)  streamIn.close();
      if (streamOut != null) streamOut.close();
   }
}

The first error is due to implements Runnable. The second I am not sure though java.io.* is imported so I am not sure why it's complaining.

ChatServer.java:34: error: cannot find symbol
         client.start();
               ^
  symbol:   method start()
  location: variable client of type ChatServerThread
like image 520
Astron Avatar asked Oct 16 '25 09:10

Astron


1 Answers

Generally speaking you don't shutdown a server because a client said bye. That means any user could connect to your server and remotely shutdown without your control. Shutting down the server is handled by the admin or owner of the server, and generally done by running a command on the server through an authenticated ssh session. On unix/linux you might run:

service chatserver stop

That's another topic how to make that work, but just to give you a general overview of best practices. Now if you want to shutdown a client when the conversation is over. That makes more sense:

public class ChatServerThread implements Runnable {

    .......

    public void run() {
        try {
            handleClient();
        } catch( EOFException eof ) {
            System.out.println("Client closed the connection.");
        } catch( IOException ioe ) {
            ioe.printStacktrace();
        }
    }

    public void handleClient() throws IOException {
       boolean done = false;
       try {
          while(!done) {  
             String nextCommand = streamIn.readUTF();
             if( nextCommand.equals(".bye") ) {
                done = true;
             } else {
                System.out.println( nextCommand );
             }
          }
       } finally {
          streamIn.close();
          streamOut.close();
          socket.close();
       }
    }
}

Then you can free up that thread to service the next client, or simply shut it down. With DataInputStream you will get a EOFException when the client closes the socket without sending a ".bye". So you can catch the EOFException before the IOException, and simply shutdown.

Notice I did not subclass Thread. Instead I implemented a Runnable which gives you more flexibility in the future should you want to create a Thread pool or something fancier.

like image 142
chubbsondubs Avatar answered Oct 17 '25 21:10

chubbsondubs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!