简体   繁体   English

如何终止由于 Socket.accept() 而被阻塞太久的线程?

[英]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.每当客户端连接时,服务器将创建一个新的从站,将该从站的 IP/端口发送给客户端,然后客户端将与从站一起工作。

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.但是,如果客户端接收到从站的地址,则什么都不做(或退出)(编辑:这意味着客户端和服务器已连接,但客户端什么也不做,因为例如用户去吃午饭) slaveSocket.accept()导致该从站线程永远运行,这是浪费。

I want the slave thread to exit after 30 second of waiting for slaveSocket.accept() .我希望从线程在等待slaveSocket.accept() 30 秒后退出。 Since slaveSocket.accept() is blocking, I cannot do that from inside the void run() .由于slaveSocket.accept()是阻塞的,我不能从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.编辑 1:将 ServerSocket 传递给从属,因为客户端可以有多个进程连接到该从属。 So it doesn't just perform one function.所以它不只是执行一个 function。

If you set a timeout with setSoTimeout and no client connects, ServerSocket.accept will throw an exception.如果您使用 setSoTimeout 设置超时并且没有客户端连接,ServerSocket.accept 将抛出异常。 You can catch this exception.您可以捕获此异常。

To set a timeout of 30 seconds, use:要将超时设置为 30 秒,请使用:

serverSocket.setSoTimeout(30000)

Non-blocking I/O:非阻塞 I/O:

Take a look at AsynchronousServerSocketChannel's accept method which returns a Future .看一下AsynchronousServerSocketChannel 的 accept方法,它返回一个Future Then the Future has a getter with timeout which can do what you are asking.然后Future有一个带超时的吸气剂,它可以做你所要求的。

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.然后 getter 将返回一个AsynchronousSocketChannel ,可以通过相应的Channels.newInputStreamChannels.newOutputStream方法将其转换回阻塞,以便与工作线程中的阻塞方法一起使用。

Blocking I/O:阻塞 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.我认为您实际上的意思是如何实现一个服务器,该服务器顺序接受客户端并并行服务它们,并阻塞 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) {}
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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