简体   繁体   中英

How to terminate a thread that has been blocked for too long due to Socket.accept()?

public class Slave implements Runnable {
   public ServerSocket slaveSocket;

   public Slave(ServerSocket sk) {socket = sk;}

   @Override
   public void run() {
      Socket client = slaveSocket.accept(); // slave will wait to serve a client
      // more code...

      Socket clientPart2 = slaveSocket.accept();
      // more code...
   }
}

public class Server {
   public static void main(String[] args) {
       // for example only, incomplete code
       ServerSocket serverSocket = new ServerSocket(0); // a client connect to 8088
       Slave slave = new Slave(serverSocket);
       new Thread(slave).start(); // slave serve the current client, the server wait for new client

       // send new slave's port to client ... 
   }
}

So I have a server that serves multiple clients at once. Whenever a client connects, the server will create a new Slave, send the IP/port of that slave to the client, then the client will work with the slave.

However, if the client receives the slave's address then do nothing (or quit) ( Edit: it means the client and server are connected but the client do nothing, because for example the user goes for lunch) slaveSocket.accept() causes that slave Thread to run forever, which is wasteful.

I want the slave thread to exit after 30 second of waiting for slaveSocket.accept() . Since slaveSocket.accept() is blocking, I cannot do that from inside the void run() .

What is the correct, clean way to solve this problem? Thank you.

Edit 1: a ServerSocket is passed to the slave because the client can have multiple processes that will connect to that slave. So it doesn't just perform one function.

If you set a timeout with setSoTimeout and no client connects, ServerSocket.accept will throw an exception. You can catch this exception.

To set a timeout of 30 seconds, use:

serverSocket.setSoTimeout(30000)

Non-blocking I/O:

Take a look at AsynchronousServerSocketChannel's accept method which returns a Future . Then the Future has a getter with timeout which can do what you are asking.

Note: you may read a related tutorial .

Then the getter will return an AsynchronousSocketChannel which can be converted back to blocking via the corresponding Channels.newInputStream and Channels.newOutputStream methods to be used with the blocking approach in the worker threads.

Blocking I/O:

I think you actually meant on how to implement a server which accepts clients sequentially and serves them in parallel, with blocking I/O. If that is the case, then you may take a look at the following example:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Objects;

public class Main {

    public static class Worker implements Runnable {
        private final Socket sck;
        private OutputStream os;
        private InputStream is;

        public Worker(final Socket sck) {
            this.sck = Objects.requireNonNull(sck);
        }

        @Override
        public void run() {
            try {
                os = sck.getOutputStream();
                is = sck.getInputStream();

                //ALL the work with the client goes here, unless you need more than one connections with him.
            }
            catch (final IOException iox) {
                System.err.println(iox);
            }
            finally {
                try { is.close(); } catch (final IOException | RuntimeException x) {}
                try { os.close(); } catch (final IOException | RuntimeException x) {}
                try { sck.close(); } catch (final IOException | RuntimeException x) {}
            }
        }
    }

    public static void main(final String[] args) {
        ServerSocket srv = null;
        try {
            srv = new ServerSocket(8088);
            while (true)
                new Thread(new Worker(srv.accept())).start();
        }
        catch (final IOException iox) {
            System.err.println(iox);
        }
        finally {
            try { srv.close(); } catch (final IOException | RuntimeException x) {}
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM