【问题标题】:ServerSocket with multiple connections but only one thread具有多个连接但只有一个线程的 ServerSocket
【发布时间】:2019-09-11 23:14:42
【问题描述】:

我正在尝试为单线程物理产品编写模拟器。它接受一个长期连接,而任何其他连接都会收到一条错误消息(在同一个线程中)。

我知道我可以使用带有两个线程的 java.net:

  • 线程 1 - 在端口 XXXX 上启动 ServerSocket 并等待 accept()。为第一个连接创建一个 Socket 和 Thread #2,并为其他连接生成错误消息。
  • 线程 2 - 处理 Socket IO。

但是我怎样才能用一个线程做到这一点,所以它的行为更像物理产品(即重复尝试连接会使线程无法处理第一个连接)?

尽量不使用第三方库,但如果这是唯一的选择,可以这样做。

谢谢!

【问题讨论】:

  • 在 java 中,您始终可以利用 JNI 在 C 中实现此功能,以供您的 java 程序使用。因为本机这种行为是由 posix 保证的,所以至少它可以在 BSD 和 GNULinux 中工作。 stackoverflow.com/questions/12861956/…
  • 你能给我们一些关于这个单线程产品和它运行的操作系统的信息吗?
  • 你没有提供足够的信息来说明你到底想要达到什么目标,并不断在 cmets 中添加额外的信息来回答。
  • @Jan 这里不需要 JNI。 Java 已经支持非阻塞accept()
  • @daniu 据我所知,我只是重申帖子中已经给出但被受访者忽略的信息。如果您可以让我知道缺少什么,很高兴在原始帖子中添加信息。

标签: java serversocket


【解决方案1】:

不幸的是,常见的java.net.ServerSocketjava.nio.channels.ServerSocketChannel 仅具有接受传入连接的阻塞方法。然而,java.nio 包具有许多其他类和方法,可通过多路复用打开的通道在单个线程中处理 I/O 操作。

这种方法仍会为接受 ServerSocketChannel 强制执行专用线程,但您可以在单个线程中处理每个接受的连接。

相比之下,ServerSocket 方法需要一个新线程用于每个新连接。
如果您使用ServerSocket 连接 100 个客户端,那么您最终将获得 101 个线程。使用ServerSocketChannel,您可能最终只使用 2 个线程。

静态编程通常需要在复杂性/灵活性和性能之间进行权衡。所以请记住这一点。

我能想到的一个可能的解决方案可能如下所示:

public static void main( String[] args ) throws IOException
{
  int portNr = 8080;

  ExecutorService es = Executors.newSingleThreadExecutor();
  ChannelHandler ch = new ChannelHandler(); 
  es.execute( ch );

  // Starting server:
  ServerSocketChannel serv = ServerSocketChannel.open();
  // Bind socket to Port
  serv.socket().bind(new InetSocketAddress(portNr));

  while( serverAlive ) 
  {
    ch.addChannel(serv.accept());
  }
  serv.close();
}

您如何实际处理新添加的SocketChannel 取决于您的应用程序。 ChannelHandler#addChannel 方法也是如此。

【讨论】:

  • java.nio.channels.ServerSocketChannel 可以进入非阻塞模式,这样它的accept() 方法就不会阻塞。
  • 解决方案看起来像非阻塞模式、Selector 和标准select() 循环。与上述完全不同。
  • 这个答案应该被接受,因为它是最好的方法!
【解决方案2】:

看来您应该接受单个连接,然后关闭ServerSocket。任何未来的连接尝试都会被拒绝连接。当长期连接结束时,创建一个新的ServerSocket,再接受一个连接,...冲洗并重复。

编辑如果您必须按照下面的评论传递错误消息,则必须接受连接才能将其发送过来,并且如果您必须进行 I/O 并接受所有功能线程你必须使用java.nio.channels.ServerSocketChannel/SocketChannel、非阻塞模式和Selector

【讨论】:

  • 谢谢,但是未来的连接尝试需要给出一个特定的字符串作为错误响应(这是为了模拟物理产品)。此字符串需要在与处理单个连接的线程相同的线程中生成。
  • @Mykro 好的,请参阅编辑。但是为什么需要在同一个线程中生成呢?模拟器之外,谁能说得清?
【解决方案3】:

在一个线程中使用 ServerSocket 根本不是一个好主意。为什么?
你知道 socket.accept() 一直等到下一个客户端连接,所以线程被阻塞,如果你只有一个线程,你的整个程序被阻塞,直到客户端连接。
你能解释一下为什么你尝试单线程吗?

【讨论】:

  • 您好,感谢您的回复。 ServerSocket 将只有一个自己的线程,它不是应用程序线程,因此它不会阻塞整个程序。但正如问题中所解释的,是的,我确实想在一个线程中处理所有连接,因为这就是我试图模拟的物理产品的功能。
  • @Mykro 对于每个客户端连接的 IO,您需要单独的 Threads,但是您可以将它们全部放入一个 Thread 进行实际处理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
  • 2023-01-17
  • 2020-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多