黑马程序员Netty全套教程,全网最全Netty深入浅出教程,Java网络编程的王者_哔哩哔哩_bilibili
三大组件
Channel & Buffer
- FileChannel
- DatagramChannel
- SocketChannel
- ServerSocketChannel
ByteBuffer
- MappedByteBuffer
- DirectByteBuffer
-
ServerSocketChannel & SocketChannel
selector
ByteBuffer
flip()切换读模式
- clear()切换写模式
ByteBuffer的指针
读取
- channel.read(buffer)
- buffer.get()
- get(i):不改变指针
- rewind():position=0
-
半包读取
转换字符串
ByteBuffer buffer1 = StandardCharsets.UTF_8.encode(“你好”);
ByteBuffer buffer2 = Charset.forName(“utf-8”).encode(“你好”);FileChannel
-
获取
写入【必须循环】
ByteBuffer buffer = …; buffer.put(…); // 存入数据 buffer.flip(); // 切换读模式
while(buffer.hasRemaining()) {
channel.write(buffer);**//向channel(socketChannel)写,不能保证一次写完。**
}
transferTo()
- 零拷贝,效率高
- 一次最多2g数据
walkfiletree遍历文件夹
walkfiletree删除多级目录
walk拷贝多级目录
nio
阻塞模式:accept & read阻塞
每次必须新建一个链接accept才能往下执行,才能执行read,read所有的channel。
可以新建一个thread来处理read请求。
非阻塞模式
- ServerSocketChannel设置为非阻塞:accept不再阻塞
- 没有连接返回null
- SocketChannel设置为非阻塞:read非阻塞
- 没有读到数据返回0
单线程处理多个客户端连接,所以引出selector
SocketChannel & ServerSocketCHannel
- 服务器必须先建立ServerSocket或者ServerSocketChannel 来等待客户端的连接
- 客户端必须建立相对应的Socket或者SocketChannel来与服务器建立连接
服务器接受到客户端的连接受,再生成一个Socket或者SocketChannel与此客户端通信
selector
多路复用:单线程使用selector对多个channel进行事件监控
channel注册到selector:SelectionKey sscKey = ssc.register(selector, 0, null);
设置SelectionKey关注的事件:
- ServerSocketChannel注册到selector
ssc.register(selector, SelectionKey.OP_ACCEPT);
- 检查是否有事件
select = selector.select(timeout)
- 从selector获取就绪key
Iterator
- 判断连接事件
key.isAcceptable()
- 从key中获取channel
SocketChannel sc = (SocketChannel) key.channel();
- 处理channel
SocketChannel sc = serverSocketChannel.accept() 处理连接请求
int write = SocketChannel.write(buffer); 处理写请求
监听channel:
- selector.select():一直阻塞,直到事件发生
- select为了让非阻塞io在没有事件时阻塞
-
Selector(所有key) & SelectedKeys(发生事件的key)
SelectedKeys:Selector中发生事件的key。
- Selector发生事件后,只会往SelectedKeys中加key,不会删除。
- 不论客户端正常断开、异常断开,都会产生一个read事件
- 判断正常断开:read()返回-1
- 异常断开:try catch
- key.cancel()表示这个key已处理。
处理消息边界
- 固定长度消息
- 按分隔符
- TLV格式,type/length/value。
attachment():关联ByteBuffer到Channel
- 绑定buffer到channel:sc.register()
- 获取:key.attachment();
写出
错误写法:
while循环阻塞
改进:
添加writable事件
多线程
io模型
多路复用
- 一个线程处理了多个客户端连接。
同步,异步区别:复制数据是自己线程复制(从内核空间复制到用户空间)还是内核线程复制。
select函数
IO多路复用到底是不是异步的? - 知乎
poll和 select 的主要区别就是,去掉了 select 只能监听 1024 个文件描述符的限制。