由于我想尝试与Telegram服务器建立基本的TCP连接(使用MTProto),因此我开始阅读有关Java NIO类的信息。但是,我为尝试理解Selector
对于客户的意义而感到“困惑”。
选择器支持基于密钥的非阻塞多路复用I / O。换句话说,选择器使您能够通过多个通道执行I / O。 ( Java-完整参考)
由于始终将TCP消息作为流进行排序,并且我将只打开一个套接字连接(单个SocketChannel
),所以使用Selector
有什么意义?我认为没有意义,对吗?
如果我的回答正确,为什么不直接使用阻止I / O?
答案 0 :(得分:1)
NIO
基本上是在服务器端使用的,以处理大规模事件。我将尝试解释典型服务器的工作方式。
服务器有一个请求队列,轮询线程从中使用连接进行blocking dequeue
操作(在Java中,请求队列的默认长度为50。这意味着如果您尝试在启动第51个连接时请求队列已满,您将获得ConnectionRefused
例外)。
典型的blocking
实现如下:
服务器接受连接并将其放在requests queue
上。
轮询thread
消耗了队列开头的连接,并将其分配给thread pool
。如果thread-pool
队列未满,则轮询线程将变为空闲状态,并继续消耗来自queue
的连接。
在某些时候,线程池中的所有线程都将变得繁忙,并且在向池提交更多连接时,轮询线程将被阻塞(因为线程池队列是blocking queue
)
与此同时,requests queue
开始填充。在某个时候,它将完全装满,服务器将不再接受任何连接。
目前,我们的服务器无法再扩展。请注意,池中的“繁忙”线程可能根本不繁忙,而只是被阻塞-例如,要获取有关它们所服务的各个套接字的InputStream
上的更多数据。
现在考虑这种设计:
轮询线程从请求队列的开头消耗项目。
它将其放入无限制列表。
另一个线程不断循环访问此列表,并检查套接字上是否发生了任何活动(读,读,准备写等)。如果有活动,则socket
被提供。请注意,这些sockets
在NIO
模式下运行。也就是说,如果没有活动,我们的线程将不会被阻塞。
由于列表不受限制,因此轮询线程在此期间继续向列表提交连接。它不会在任何地方被阻止(正在等待请求队列上的新连接时除外)。
在上述设计中,请注意,我们的规模仅受系统资源的限制,即list
拥有多少个连接。由于只有一个线程为所有连接提供服务,因此响应时间会受到影响。由于不经意的迭代,您的CPU消耗将非常高。但是,与以前的设计不同,您仍然可以连接到服务器。
NIO
基本上通过使用selectors
解决了这个问题。