java nio 网络编程
三要素
- Channel:通道,想象成自来水管,所有的数据都要通道来传递
- Buffer:缓冲区,负责从通道中读写数据,注意,读是从通道中读到缓冲,写是从缓冲写入通道
- Selector:多路复用器,负责监视通道,如果通道的数据就绪,可以通过 Selector 获取 SelectionKey 进而得到就绪状态的 Channel 集合
打个比方
缓冲区就是水桶,通道是自来水管,多路复用器是保安。
这里有个保安,负责看守所有的水管,你要新建一个连接也就是要新加一个水管,那么你需要注册,也就是告诉保安。当然,你还要告诉保安,这根水管在什么情况下,你需要保安给你反馈。比如有人来接水了,有人来存水了,水龙头打开了等。
所以你知道了,我们的自来水管是双向的,可以接水,也可以存水。缓冲区也就是水桶,就是负责接水或者存水的装置。写数据就是将水桶的水往水管存,读数据就是将水管的水往水桶倒。
看张图:
从图中可以看出,服务器上所有Channel(包括ServerSocketChannel和SocketChannel)都需要向Selector注册,而该Selector则负责监视这些Socket的IO状态,当其中任意一个或者多个Channel具有可用的IO操作时,该Selector的select()方法将会返回大于0的整数,该整数值就表示该Selector上有多少个Channel具有可用的IO操作,并提供了selectedKeys()方法来返回这些Channel对应的SelectionKey集合。正是通过Selector,使得服务器端只需要不断地调用Selector实例的select()方法即可知道当前所有Channel是否有需要处理的IO操作。
类与方法
-
创建多路复用器:
Selector selector = Selector.open();
-
创建服务端通道:
ServerSocketChannel servChannel = ServerSocketChannel.open();
-
通道设置为非阻塞:
servChannel.configureBlocking(false);
-
通道绑定端口:
servChannel.socket().bind(new InetSocketAddress(port), 1024);
-
通道注册到复用器,监听接收操作:
servChannel.register(selector, SelectionKey.OP_ACCEPT);
-
获取就绪状态 Channel,每秒轮询:
int num = selector.select(1000);
-
返回就绪状态的 Channel 的 SellectionKey 集合:
Set<SelectionKey> selectedKeys = selector.selectedKeys();
- 对就绪状态的 Channel 集合进行迭代,进行网络的异步读写操作
SelectionKey 的操作
-
isValid()
是否可用 -
isAcceptable()
新连接到来,然后获取 channel 转成 SocketServerChannel,再然后调用 accept 获取 SocketChannel,将 SocketChannel 注册到 Selector 上 -
isReadable()
Channel 已就绪,直接读就可以了 -
isConnectable()
通道是否已连接 -
channel()
获取通道
版权声明:本文为m0_37659871原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。