Java 具有多个连接但只有一个线程的ServerSocket

Java 具有多个连接但只有一个线程的ServerSocket,java,serversocket,Java,Serversocket,我正在尝试为单线程物理产品编写一个模拟器。它接受一个长期存在的连接,而任何其他连接都会收到一条错误消息(在同一线程中) 我知道我可以通过两个线程使用java.net: 线程1-在端口XXXX上启动ServerSocket并等待accept()。对于第一个连接,创建套接字和线程#2,对于其他连接,生成错误消息 线程2-处理套接字IO 但是我如何使用一个线程来实现它,使它的行为更像物理产品(即重复尝试连接会使线程无法处理第一个连接) 尽量不使用第三方库,但如果这是唯一的选择,可以这样做 谢谢 使

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

我知道我可以通过两个线程使用java.net:

  • 线程1-在端口XXXX上启动ServerSocket并等待accept()。对于第一个连接,创建套接字和线程#2,对于其他连接,生成错误消息
  • 线程2-处理套接字IO
但是我如何使用一个线程来实现它,使它的行为更像物理产品(即重复尝试连接会使线程无法处理第一个连接)

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


谢谢

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


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

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

相比之下,
ServerSocket
方法需要为每个新连接添加一个新线程。
如果您使用
ServerSocket
连接100个客户端,那么您将得到101个线程。使用
ServerSocketChannel
可以只使用两个线程

静态编程通常是关于复杂性/灵活性和性能之间的权衡。所以请记住这一点

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

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
方法也是如此。

您似乎应该接受单一连接,然后关闭
服务器套接字。以后的任何连接尝试都将被拒绝。当长期连接结束时,创建一个新的
ServerSocket
,再接受一个连接。。。冲洗并重复


编辑如果您必须根据下面的评论发送错误消息,您必须接受连接才能将其发送过来,如果您必须在一个线程中执行I/O并接受所有操作,则必须使用
java.nio.channels.ServerSocketChannel/SocketChannel
、非阻塞模式和
选择器,谢谢你的回复。ServerSocket只有一个自己的线程,而不是应用程序线程,因此它不会阻塞整个程序。但正如问题中所解释的,是的,我确实希望在一个线程中处理所有连接,因为这就是我试图模拟的物理产品的工作方式。@Mykro对于每个客户端连接的IO,您将需要单独的
thread
s,但是,您可以让它们全部进入一个
线程
进行实际处理。因为posix在本质上保证了这种行为,所以至少它可以在BSD和GNULinux中工作。你能给我们一些关于这个单线程产品和它正在运行的操作系统的信息吗?你没有给出足够的关于你到底想要实现什么的信息,并且不断在答案的注释中添加额外的信息。@Jan这里不需要JNI。Java已经支持非阻塞的
accept()
@daniu。据我所知,我只是在重复帖子中已经给出的信息,这些信息被回复者忽略了。如果您能告诉我缺少什么,很高兴为原始帖子添加信息。
java.nio.channels.ServerSocketChannel
可以进入非阻塞模式,这样它的
accept()
方法就不会阻塞。解决方案看起来像是非阻塞模式、一个
选择器和一个标准的
select()
循环。没有什么能像上面那样。这个答案应该被接受,因为这是最好的方式!谢谢,但是未来的连接尝试需要指定一个特定的字符串作为错误响应(这是为了模拟物理产品)。此字符串需要与处理单个连接的线程在同一线程中生成。@Mykro确定,请参阅编辑。但是为什么它需要在同一个线程中生成呢?在模拟器之外,谁能说出来?