如何在Java中将已接受的套接字设置为非阻塞

6
我正在接受客户端的连接,并将已连接的套接字传递给另一个对象,但该套接字需要是非阻塞的。我尝试使用 getChannel().configureBlocking(false),但似乎并不起作用。它需要是非阻塞的,因为下面的方法每100毫秒调用一次。我应该用其他方式使其非阻塞吗?感谢任何帮助!
public void checkForClients() {
  DataOutputStream out;
  DataInputStream in;
  Socket connection;
  InetAddress tempIP;
  String IP;

  try {
     connection = serverSocket.accept();
     connection.getChannel().configureBlocking(false);

     System.err.println("after connection made");

     in = new DataInputStream(connection.getInputStream());
     out = new DataOutputStream(connection.getOutputStream());
     tempIP = connection.getInetAddress();
     IP = tempIP.toString();

     System.err.println("after ip string");

     // create a new user ex nihilo
     connectedUsers.add(new ConnectedUser(IP, null, connection, in, out));


     System.err.println("after add user");
  } catch (SocketTimeoutException e) {
     System.err.println("accept timeout - continuing execution");
  } catch (IOException e) {
     System.err.println("socket accept failed");
  }
}

此问题已在此线程中得到解答 https://dev59.com/iGUp5IYBdhLWcg3wEEXd。答案是将服务器套接字放入其自己的线程中。 - John Deverall
5个回答

12

两件事:

  1. 你监听连接时,为什么不使用ServerSocket
  2. 如果您想接受多个客户端,则应使用循环。

多客户端服务器的基本结构是:

while (true) {
  // accept connections
  // spawn thread to deal with that connection
}
如果问题在于 accept() 调用上被阻塞,那么这正是 accept() 的作用:它会阻塞等待连接。如果这是个问题,建议您开启一个单独的线程来接受连接。
参见编写 Socket 的服务器端

这并不回答问题,但在大多数情况下,这是正确的方法 - 如果您真的想要非阻塞IO,请使用其他答案中提到的nio包(但这也意味着没有流!) - rurouni
@rurouni,没有答案,因为你不能不转移到NIO就完成它。 - user207421

1

我希望你的代码在accept调用上阻塞,从未到达configureBlocking调用。

通常我会为每个套接字连接启动一个单独的线程,并让它阻塞直到实际建立/接受连接。这样可以使主线程在等待客户端连接时继续不被阻塞。


1

0
如果典型的阻塞套接字无法提供您所需的可用性(每100毫秒建立一次连接似乎很紧张),那么您应该考虑使用非阻塞套接字。这里有一个教程。您还可以查看Apache MINA,以使此过程更加容易。

0

一种方法是在单线程环境中使用 I/O 循环(事件循环)。可以参考 Deft web server 来获得灵感。(尤其是在 IOLoop 中的 start() 方法)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接