Socket vs SocketChannel

Ram*_*hil 66 java sockets socketchannel

我试图了解SocketChannelsNIO.我知道如何使用常规套接字以及如何创建一个简单的每个客户端线程服务器(使用常规阻塞套接字).

所以我的问题:

  • 什么是SocketChannel?
  • 使用SocketChannel而不是Socket时,我获得了多少额外的东西.
  • 通道和缓冲区之间有什么关系?
  • 什么是选择器?
  • 文档中的第一个代码是A selectable channel for stream-oriented connecting sockets..那是什么意思?

我已经阅读了这个文档,但不知怎的,我没有得到它...

And*_*Mao 53

A Socket是阻塞输入/输出设备.它Thread使用它来阻止读取,如果底层缓冲区已满,可能还会阻止写入.因此,如果您的服务器有一堆open Sockets ,则必须创建一堆不同的线程.

A SocketChannel是一种从套接字读取的非阻塞方式,因此您可以让一个线程同时与一堆打开的连接进行通信.这通过向a添加一堆SocketChannels Selector,然后在选择器的select()方法上循环来工作,如果套接字已被接受,接收数据或已关闭,则可以通知您.这允许您在一个线程中与多个客户端通信,而不会有多个线程和同步的开销.

Buffers是NIO的另一个功能,它允许您从读取和写入访问基础数据,以避免将数据复制到新阵列的开销.

  • 术语只有在被滥用时才会引起混淆."NIO"中的"非阻塞"属于"IO",即I/O操作.该线程没有"浪费",因为它无关_Except_ I/O. 非阻塞I/O与异步I/O不同:这是一个完全不同的主题. (10认同)
  • @AndrewMao您确实可以使用没有选择器的通道,即使在非阻塞模式下也是如此,这不是默认设置,尽管不推荐这样做。“NIO”中的“N”代表“New”。 (3认同)
  • 例如,您不能在没有选择器的情况下使用通道,因为选择器会告诉您何时准备好读取通道。我想不出你想要自己使用通道的原因,因为你基本上会重新实现选择器的功能。 (2认同)

ara*_*yq2 17

到现在NIO为止,很少有人记得1.4之前的Java是什么样的,这是你需要知道的,以便理解"为什么" NIO.

简而言之,在Java 1.3之前,所有I/O都是阻塞类型.更糟糕的是,没有模拟select()系统调用多路复用I/O. 因此,用Java实现的服务器别无选择,只能采用"每个连接一个线程"的服务策略.

在Java 1.4中引入的NIO的基本要点是使Java中可用的传统UNIX样式多路复用非阻塞I/O的功能.如果您了解如何编程select()poll()检测一组文件描述符(通常是套接字)上的I/O就绪状态,那么您将找到所需的服务NIO:您将使用SocketChannels作为非阻塞I/O端点和Selectors用于fdsets或pollfd数组.现在可以使用具有线程池的服务器,或者每个处理多个连接的线程的服务器.这是"额外的".

A Buffer是非阻塞套接字I/O所需的字节数组,特别是在输出/写入端.如果只能立即写入缓冲区的一部分,使用阻塞I/O,您的线程将直接阻塞,直到可以写入整体.使用非阻塞I/O,您的线程获得写入了多少的返回值,由您来处理下一轮的剩余部分.A Buffer通过显式实现生产者/消费者模式来填充和排空来处理这些机械细节,可以理解您的线程和JVM的内核不会同步.

  • 听起来你已经将非阻塞I/O与异步I/O混为一谈.即使在异步I/O中,阻塞也不会"完全消除" - 例如,Future <>上的get()是一个阻塞调用.设计问题不是_tother_阻止(你的基本混乱),而是_when_阻止. (3认同)
  • 真?那么自从在Java 1.4中引入NIO以来,configureBlocking(bool)方法发生了什么? (2认同)

Fra*_*ang 5

即使您正在使用SocketChannels,也必须使用线程池进行处理channels

考虑到scenairo,您仅使用一个线程负责轮询select()和处理SocketChannels从中选择的线程Selectors,如果一个通道处理需要1秒,并且队列中有10个通道,则意味着您必须等待10秒才能进行下一次轮询是无法忍受的。因此应该有一个线程池用于通道处理。

从这个意义上说,我认为每个客户端线程阻塞套接字模式没有太大区别。主要区别在于NIO模式,任务更小,更像每个任务线程,并且可以读取,写入,biz流程等任务。有关更多详细信息,您可以查看Netty的实现NioServerSocketChannelFactory,正在使用一个Boss线程接受连接,并将任务分派到Worker线程池中进行处理

如果您真的很喜欢一个线程,那么最起码您至少应该拥有池化的I / O线程,因为I / O操作通常比指令处理周期慢很多,因此您不希望使用宝贵的一个线程被I / O阻塞,这正是NodeJS所做的,使用一个线程接受连接,并且所有I / O都是异步的,并由后端I / O线程池并行处理

旧样式的每个客户端线程已死? 我不这么认为,NIO编程很复杂,并且多线程并不是天生的邪恶,请记住,现代操作系统和CPU在多任务处理方面变得越来越好,因此多线程的开销随着时间的推移而变得越来越小。