最近学netty,顺便把nio学了,做个记录(需要有基础)
我的理解
原来io流当获取数据时,会保持阻塞状态,现在改为nio非阻塞,那我不在这一直等着,我怎么知道什么时候他来数据,这时出来一个selector,充当监听器,可以选择隔一段时间来看有没有客户端传来数据,在这里,所有传送的请求被封装成了一个key,相当于,你现在可以有好多个客户端同时给服务器发送请求,请求全部堆在channel中,你selector什么时候有空了就来看下,然后取出所有的key,一下处理好多个请求,这就是nio主要做的
深入理解
- 为什么将serverSocketChannel也注册到了selector上
其实ssc.register,将一个serverSocketChannel注册到selector上,也就是说,此时服务器也当作一个普通的channel注册到selector上,并且这个监听的事件是accept,也就是说当有客户端连接时,你可以在key集合中判断这个链接是不是最初建立的(selectionKey.isAcceptable()),如果是,那么你就要为这个最初生成的通道建立一些东西了,创建一个socketChannel,并注册到selector上,注意一般ssc才会注册accept,我们客户端和服务端一般都是监听read,wright并不需要监听,你需要写时就写就行了
上面说了情况是你将ssc注册到了selector上了,当然你也可以自己想象下,一个客户端来时你本来就要为其accept()一个通道,这里这是交给了selecor处理这个accept监听,然后在上图的模块处理,本质没有什么区别 - 客户端为什么也要写selector
因为,客户端需要非阻塞监听服务器发送过来的数据时,也必须创建一个监听器,所以也要创建 - channel通道可以互不影响的双向传输数据吗
是的,服务器向公共channel里添加数据,此时会在客户端对应channel的selector上出现一个read事件,你可以获取selectorKey处理此次事件,同时客户端向公共channel里添加数据,也会在服务端端对应channel的selector上出现一个read事件,两者互不影响,就像bio里你开了socket后获取的input和output一样,两者互不影响
注意事项
- 每次处理完一个selectorKey时一定不要忘记去除此事件,即使在客户端,
- 向buffer中put数据后,一定要flip,转换模式
- 你可以selector.selectedKeys()获取所有注册的通道,但是别忘了其中还有一个serverSocketChannel,与其他socketChannel不同,需要单独处理
总结:一句话,创建个selector监听,什么时候有信号了处理就行,一开始时先创建serviceSocketChannel绑定在这个selector上accepter