Netty - NIO 之 Selector模式

回到顶部(go to top)

一、总结

豁然开朗,之前以为非阻塞的实现是因为selector。现在才知道selector的为了让非阻塞变成更好:

  • 无事件时,阻塞
  • 有事件时,非阻塞

 

回到顶部(go to top)

二、背景知识

2.1 事件的类型

 

回到顶部(go to top)

三、Selector 模式

3.1 selector 处理accept事件

 

 

3.2 selector 取消事件

如果selector观测到了accept事件,而代码没有处理.那么此时selector.select()函数就不会阻塞,代码又会进入无限循环的模式...

因为selector会认为没有处理的事件,依然为新事件,所以会不停的把该事件放进selector.selectedKeys

 

 

事件发生后,要么处理,要么取消。不能置之不理。

 

 

3.3 selector read事件

 

 

由于iter是循环的selector上面所有的key,因此包含了ServerSocketChannel注册的key,也包括SocketChannel注册的key。

  • ServerSocketChannel注册的key,关心accept事件。(代码1,说明当ServerSocketChannel接收到accept时间后,会把接收到的SocketChannel也注册进selector里面)
  • SocketChannel注册的key,关心read事件

因此在循环里,需要区别对待。

 

1)为何处理过的SelectionKey,要手动删除?

  • 当channel向selector注册时(红色横线标注的代码),会生成一个SelectionKey,放入红色框中,还会记录该key感兴趣的是哪个事件,已经对于的是哪个channel.
  • 当有事件触发时,seletor.select()会接收到,并把事件对应的SelectionKey放入绿色的框中(此时依然会携带该SelectionKey感兴趣的是哪个事件)。但是一旦处理了该事件(例如是accept事件:对应着channel.accept()),绿色框中的SelectionKey就会抹去感兴趣的时间。如果不主动删除,一旦下次循环再次来到channel.accept(),就会返回null.

 

 

因此,要手动清除处理过的SelectionKey。

  • 这里的remove()是从绿色的框中,移除。
  • 但key.cancel()是从红色的框中,移除。

 

 

2)处理 客户端断开 问题

无论是 异常断开 还是 正常断开,都会自动触发一个read事件。

key.cancel()是从红色的框(selector的keys集合)中,移除

 

3)处理 消息边界 问题

问题描述

UTF-8编码中,一个中文是3个字节。由于服务器的buffer里面,只设置了4个字节。因此:

  • 第一次读取是完整的“中”,加上三分之一的“国”
  • 第二次读取是剩下三分之二的“国”

因此输出中,只有“中”是正常显示,其余都是乱码。

 

 

不完美的解决方案

如果buffer空间不够,就扩容。扩容后的新buffer需要把之前的数据copy过来,再去读新的数据。

 

 

 

注意点:如何把buffer和SelectionKey关联

selector会关联多个channel,可能同时有多个channel有read事件。如果公用一个buffer,内容就会乱掉。

因此必须一个channel,一个buffer。

这里就用到了,channel在像selector注册时的第三个参数att...

 

回到顶部(go to top)

Tips: selector何时不阻塞

 

posted on   frank_cui  阅读(171)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

levels of contents
点击右上角即可分享
微信分享提示