[英]Socket vs SocketChannel
我试图了解SocketChannels和NIO 。 我知道如何使用常规套接字以及如何创建一个简单的每个客户端线程服务器(使用常规阻塞套接字)。
所以我的问题:
A selectable channel for stream-oriented connecting sockets.
。 那是什么意思? 我已经阅读了这个文档 ,但不知怎的,我没有得到它...
Socket
是阻塞输入/输出设备。 它使正在使用它的Thread
阻塞读取,如果底层缓冲区已满,则可能还会阻止写入。 因此,如果您的服务器有一堆打开的Socket
,您必须创建一堆不同的线程。
SocketChannel
是一种从套接字读取的非阻塞方式,因此您可以让一个线程同时与一堆打开的连接进行通信。 这可以通过向Selector
添加一堆SocketChannel
,然后在选择器的select()
方法上循环,该方法可以通知您是否已接受套接字,接收数据或已关闭。 这允许您在一个线程中与多个客户端通信,而不会有多个线程和同步的开销。
Buffer
是NIO的另一个功能,它允许您从读取和写入访问基础数据,以避免将数据复制到新阵列的开销。
到目前为止, NIO
已经很老了,很少有人记得1.4之前的Java是什么样的,这是你需要知道的,以便了解NIO
的“原因”。
简而言之,在Java 1.3之前,所有I / O都是阻塞类型。 更糟糕的是,没有模拟select()
系统调用Multiplex I / O. 因此,用Java实现的服务器别无选择,只能采用“每个连接一个线程”的服务策略。
在Java 1.4中引入的NIO的基本要点是使Java中可用的传统UNIX样式多路复用非阻塞I / O的功能。 如果您了解如何使用select()
或poll()
来编程来检测一组文件描述符(通常是套接字)上的I / O就绪状态,那么您将在NIO
找到所需的服务:您将使用SocketChannel
用于非阻塞I / O端点,以及用于fdsets或pollfd数组的Selector
。 现在可以使用具有线程池的服务器,或者每个处理多个连接的线程的服务器。 这是“额外的”。
Buffer
是非阻塞套接字I / O所需的字节数组,特别是在输出/写入端。 如果只能立即写入缓冲区的一部分,使用阻塞I / O,您的线程将直接阻塞,直到可以写入整体。 使用非阻塞I / O,您的线程会获得写入多少的返回值,由您来处理下一轮的剩余部分。 Buffer
通过显式实现生成器/消费者模式来填充和排空来处理这些机械细节,可以理解您的线程和JVM的内核不会同步。
即使您使用SocketChannels
,也必须使用线程池来处理channels
。
考虑到scenairo你只使用一个线程负责轮询select()
和处理从Selectors
的SocketChannels
,如果一个通道需要1秒进行处理,并且队列中有10个通道,则意味着你必须等待10下次轮询之前的几秒钟,这是不可容忍的。 所以应该有一个用于频道处理的线程池。
从这个意义上讲,我没有看到每个客户端线程阻塞套接字模式的巨大差异。 主要的区别在于NIO
模式,任务更小,更像是每个任务的线程,任务可以是读,写,流程等等更多细节,你可以看看Netty的NioServerSocketChannelFactory
的实现,它使用一个Boss线程接受连接,并将任务分派给一个工作线程池进行处理
如果你真的很喜欢一个线程,那么底线是至少你已经汇集了I / O线程,因为I / O操作通常比指令处理周期慢一些,你不会想要珍贵的一个线程被I / O阻塞,这正是NodeJS所做的,使用一个线程接受连接,并且所有I / O都是异步的并且由后端I / O线程池并行处理
是每个客户端的老式线程死了吗? 我不这么认为,NIO编程很复杂,多线程并不自然是邪恶的。请记住,现代操作系统和CPU在多任务处理中变得越来越好,因此多线程的开销随着时间的推移变得越来越小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.