【问题标题】:How to terminate a thread that has been blocked for too long due to Socket.accept()?如何终止由于 Socket.accept() 而被阻塞太久的线程?
【发布时间】:2020-04-03 15:45:27
【问题描述】:
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 ... 
   }
}

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

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

我希望从线程在等待slaveSocket.accept() 30 秒后退出。由于slaveSocket.accept() 被阻塞,我无法从void run() 内部执行此操作。

解决这个问题的正确、干净的方法是什么?谢谢。

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

【问题讨论】:

  • Read the Javadoc,特别是抛出 SocketTimeoutException 的原因。
  • 每当客户端连接时,服务器都会创建一个新的 Slave...但是我可以看到您将 ServerSocket 传递给 Slave 工作线程类。 ..你想达到什么目的?我问是因为工作线程(或Slave 类)通常用于为客户端服务。因此,您应该(通常至少)将单个 Socket 实例传递给 Slave 类以服务单个(已接受)客户端。
  • 另外,客户端在第一次连接时已经知道服务器的IP和端口。至少在这种情况下,您不需要将其发送给他。您已经可以在Slave 类中使用名为clientSocket。无需创建另一个套接字。也不需要向他发送 IP+端口,因为客户端已经知道它首先要连接。除非您向他发送另一台服务器的 IP+端口。这就是为什么(底线)我在问你想要实现什么。
  • “但是,如果客户端收到从站的地址,则什么也不做(或退出)......”我无法解析也无法理解这句话。也许重写?
  • @gthanop 客户端包含多个进程,每个进程都需要单独与从站一起工作。所以slave不能和Server使用同一个socket,因为server仍然需要接受新来的客户端(或者我可以用同一个socket吗?我没试过)

标签: java multithreading sockets runnable blocking


【解决方案1】:

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

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

serverSocket.setSoTimeout(30000)

【讨论】:

  • 大声笑。我不知道这么简单。 +1。
  • 哇,这超级简单,几乎没有什么不便。谢谢
【解决方案2】:

非阻塞 I/O:

查看返回FutureAsynchronousServerSocketChannel's accept 方法。然后Future 有一个getter with timeout,它可以满足您的要求。

注意:您可以阅读related tutorial

然后,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) {}
        }
    }
}

【讨论】:

  • 谢谢。我试过这个,发现客户端可能需要建立多个连接。所以这还不够
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-15
相关资源
最近更新 更多