简体   繁体   English

Socket vs SocketChannel

[英]Socket vs SocketChannel

I am trying to understand SocketChannels , and NIO in general. 我试图了解SocketChannelsNIO I know how to work with regular sockets and how to make a simple thread-per-client server (using the regular blocking sockets). 我知道如何使用常规套接字以及如何创建一个简单的每个客户端线程服务器(使用常规阻塞套接字)。

So my questions: 所以我的问题:

  • What is a SocketChannel? 什么是SocketChannel?
  • What is the extra I get when working with a SocketChannel instead of a Socket. 使用SocketChannel而不是Socket时,我获得了多少额外的东西。
  • What is the relationship between a channel and a buffer? 通道和缓冲区之间有什么关系?
  • What is a selector? 什么是选择器?
  • The first sentance in the documentation is A selectable channel for stream-oriented connecting sockets. 文档中的第A selectable channel for stream-oriented connecting sockets. . What does that mean? 那是什么意思?

I have read the also this documentation , but somehow I am not getting it... 我已经阅读了这个文档 ,但不知怎的,我没有得到它...

A Socket is a blocking input/output device. Socket是阻塞输入/输出设备。 It makes the Thread that is using it to block on reads and potentially also block on writes if the underlying buffer is full. 它使正在使用它的Thread阻塞读取,如果底层缓冲区已满,则可能还会阻止写入。 Therefore, you have to create a bunch of different threads if your server has a bunch of open Socket s. 因此,如果您的服务器有一堆打开的Socket ,您必须创建一堆不同的线程。

A SocketChannel is a non-blocking way to read from sockets, so that you can have one thread communicate with a bunch of open connections at once. SocketChannel是一种从套接字读取的非阻塞方式,因此您可以让一个线程同时与一堆打开的连接进行通信。 This works by adding a bunch of SocketChannel s to a Selector , then looping on the selector's select() method, which can notify you if sockets have been accepted, received data, or closed. 这可以通过向Selector添加一堆SocketChannel ,然后在选择器的select()方法上循环,该方法可以通知您是否已接受套接字,接收数据或已关闭。 This allows you to communicate with multiple clients in one thread and not have the overhead of multiple threads and synchronization. 这允许您在一个线程中与多个客户端通信,而不会有多个线程和同步的开销。

Buffer s are another feature of NIO that allows you to access the underlying data from reads and writes to avoid the overhead of copying data into new arrays. Buffer是NIO的另一个功能,它允许您从读取和写入访问基础数据,以避免将数据复制到新阵列的开销。

By now NIO is so old that few remember what Java was like before 1.4, which is what you need to know in order to understand the "why" of NIO . 到目前为止, NIO已经很老了,很少有人记得1.4之前的Java是什么样的,这是你需要知道的,以便了解NIO的“原因”。

In a nutshell, up to Java 1.3, all I/O was of the blocking type. 简而言之,在Java 1.3之前,所有I / O都是阻塞类型。 And worse, there was no analog of the select() system call to multiplex I/O. 更糟糕的是,没有模拟select()系统调用Multiplex I / O. As a result, a server implemented in Java had no choice but to employ a "one-thread-per-connection" service strategy. 因此,用Java实现的服务器别无选择,只能采用“每个连接一个线程”的服务策略。

The basic point of NIO, introduced in Java 1.4, was to make the functionality of traditional UNIX-style multiplexed non-blocking I/O available in Java. 在Java 1.4中引入的NIO的基本要点是使Java中可用的传统UNIX样式多路复用非阻塞I / O的功能。 If you understand how to program with select() or poll() to detect I/O readiness on a set of file descriptors (sockets, usually), then you will find the services you need for that in NIO : you will use SocketChannel s for non-blocking I/O endpoints, and Selector s for fdsets or pollfd arrays. 如果您了解如何使用select()poll()来编程来检测一组文件描述符(通常是套接字)上的I / O就绪状态,那么您将在NIO找到所需的服务:您将使用SocketChannel用于非阻塞I / O端点,以及用于fdsets或pollfd数组的Selector Servers with threadpools, or with threads handling more than one connection each, now become possible. 现在可以使用具有线程池的服务器,或者每个处理多个连接的线程的服务器。 That's the "extra". 这是“额外的”。

A Buffer is the kind of byte array you need for non-blocking socket I/O, especially on the output/write side. Buffer是非阻塞套接字I / O所需的字节数组,特别是在输出/写入端。 If only part of a buffer can be written immediately, with blocking I/O your thread will simply block until the entirety can be written. 如果只能立即写入缓冲区的一部分,使用阻塞I / O,您的线程将直接阻塞,直到可以写入整体。 With non-blocking I/O, your thread gets a return value of how much was written, leaving it up to you to handle the left-over for the next round. 使用非阻塞I / O,您的线程会获得写入多少的返回值,由您来处理下一轮的剩余部分。 A Buffer takes care of such mechanical details by explicitly implementing a producer/consumer pattern for filling and draining, it being understood that your threads and the JVM's kernel will not be in sync. Buffer通过显式实现生成器/消费者模式来填充和排空来处理这些机械细节,可以理解您的线程和JVM的内核不会同步。

Even though you are using SocketChannels , It's necessary to employ thread pool to process channels . 即使您使用SocketChannels ,也必须使用线程池来处理channels

Thinking about the scenairo you use only one thread which is responsible for both polling select() and processing the SocketChannels selected from Selectors , if one channel takes 1 seconds for processing, and there are 10 channels in queue, it means you have to wait 10 seconds before next polling which is untolerable. 考虑到scenairo你只使用一个线程负责轮询select()和处理从SelectorsSocketChannels ,如果一个通道需要1秒进行处理,并且队列中有10个通道,则意味着你必须等待10下次轮询之前的几秒钟,这是不可容忍的。 so there should be a thread pool for channels processing. 所以应该有一个用于频道处理的线程池。

In this sense, i don't see tremendous difference to the thread-per-client blocking sockets pattern. 从这个意义上讲,我没有看到每个客户端线程阻塞套接字模式的巨大差异。 the major difference is in NIO pattern, the task is smaller, it's more like thread-per-task, and tasks could be read, write, biz process etc. for more detail, you can take a look at Netty 's implementation of NioServerSocketChannelFactory , which is using one Boss thread accepting connection, and dispatch tasks to a pool of Worker threads for processing 主要的区别在于NIO模式,任务更小,更像是每个任务的线程,任务可以是读,写,流程等等更多细节,你可以看看NettyNioServerSocketChannelFactory的实现,它使用一个Boss线程接受连接,并将任务分派给一个工作线程池进行处理

If you are really fancy at one thread, the bottom-line is at least you shold have pooled I/O threads, because I/O operations is often oders of magnitude slower than instruction-processing cycles, you would not want the precious one thread being blocked by I/O, and this is exactly NodeJS doing, using one thread accept connection, and all I/O are asynchornous and being parallelly processed by back-end I/O threads pool 如果你真的很喜欢一个线程,那么底线是至少你已经汇集了I / O线程,因为I / O操作通常比指令处理周期慢一些,你不会想要珍贵的一个线程被I / O阻塞,这正是NodeJS所做的,使用一个线程接受连接,并且所有I / O都是异步的并且由后端I / O线程池并行处理

is the old style thread-per-client dead? 是每个客户端的老式线程死了吗? I don't think so, NIO programming is complex, and multi-threads is not naturally evil, Keep in mind that modern operating systems and CPU's become better and better at multitasking, so the overheads of multithreading becomes smaller over time. 我不这么认为,NIO编程很复杂,多线程并不自然是邪恶的。请记住,现代操作系统和CPU在多任务处理中变得越来越好,因此多线程的开销随着时间的推移变得越来越小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM