繁体   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 ... 
   }
}

所以我有一台服务器可以同时为多个客户端提供服务。 每当客户端连接时,服务器将创建一个新的从站,将该从站的 IP/端口发送给客户端,然后客户端将与从站一起工作。

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

我希望从线程在等待slaveSocket.accept() 30 秒后退出。 由于slaveSocket.accept()是阻塞的,我不能从void run()内部做到这一点。

解决此问题的正确,干净的方法是什么? 谢谢你。

编辑 1:将 ServerSocket 传递给从属,因为客户端可以有多个进程连接到该从属。 所以它不只是执行一个 function。

如果您使用 setSoTimeout 设置超时并且没有客户端连接,ServerSocket.accept 将抛出异常。 您可以捕获此异常。

要将超时设置为 30 秒,请使用:

serverSocket.setSoTimeout(30000)

非阻塞 I/O:

看一下AsynchronousServerSocketChannel 的 accept方法,它返回一个Future 然后Future有一个带超时的吸气剂,它可以做你所要求的。

注意:您可以阅读相关教程

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

阻塞 I/O:

我认为您实际上的意思是如何实现一个服务器,该服务器顺序接受客户端并并行服务它们,并阻塞 I/O。 如果是这种情况,那么您可以查看以下示例:

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