Netty
2022-02-22 17:41:52 1 举报
AI智能生成
netty详解
作者其他创作
大纲/内容
ServerSocket serverSocket = new ServerSocket(9000);
创建一个socker
阻塞方法
Socket clientSocket = serverSocket.accept();
等待客户端连接
read是阻塞方法
byte[] bytes = new byte[1024];int read = clientSocket.getInputStream().read(bytes);
接受客户端数据
clientSocket.getOutputStream().write("HelloClient".getBytes());
clientSocket.getOutputStream().flush();
响应客户端数据
服务端
创建客户端socker
socket.getOutputStream().write("HelloServer".getBytes());socket.getOutputStream().flush();
向服务端发数据
byte[] bytes = new byte[1024];
socket.getInputStream().read(bytes);socket.close();
接受服务端回传的数据
客户端
实现
IO代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源
如果线程很多,会导致服务器线程太多,压力太大,比如C10K问题
缺点
BIO 方式适用于连接数目比较小且固定的架构, 这种方式对服务器资源要求比较高, 但程序简单易理解。
应用场景
BIO
ServerSocketChannel serverSocket = ServerSocketChannel.open();serverSocket.socket().bind(new InetSocketAddress(9000));
创建NIO服务端socket
serverSocket.configureBlocking(false);
设置ServerSocketChannel为非阻塞
SocketChannel socketChannel = serverSocket.accept();
非阻塞模式accept方法不会阻塞,否则会阻塞NIO的非阻塞是由操作系统内部实现的,底层调用了linux内核的accept函数
socketChannel.configureBlocking(false);
channelList.add(socketChannel);
设置非阻塞并保存在list中
Iterator<SocketChannel> iterator = channelList.iterator();while (iterator.hasNext()) {SocketChannel sc = iterator.next();ByteBuffer byteBuffer = ByteBuffer.allocate(128);int len = sc.read(byteBuffer); // 非阻塞模式read方法不会阻塞,否则会阻塞if (len > 0) {System.out.println("接收到消息:" + new String(byteBuffer.array()));}else if (len == ‐1) { // 如果客户端断开,把socket从集合中去掉iterator.remove();}}
遍历连接进行数据读取
服务端(没有引入多路复用)
创建NIO ServerSocketChannel
Selector selector = Selector.open();
打开Selector处理Channel,即创建epoll
把ServerSocketChannel注册到selector上,并且selector对客户端accept连接操作感兴趣
selector.select();
阻塞等待需要处理的事件发生
Set<SelectionKey> selectionKeys = selector.selectedKeys();
获取selector中注册的全部事件的 SelectionKey 实例
Iterator<SelectionKey> iterator = selectionKeys.iterator();
遍历SelectionKey对事件进行处理
服务端(引入多路复用)
NIO方式适用于连接数目多且连接比较短(轻操作) 的架构, 比如聊天服务器, 弹幕系统, 服务器间通讯,编程比较复杂
Channel(通道)
Buffer(缓冲区)
Selector(多路复用器)
三大核心组件
底层:调用linux内核函数epoll_create创建epoll实例(epfd=epoll_create(256))
Selector.open() //创建多路复用器
将fd(socketChannel)添加到内部的集合里
socketChannel.register() //将channel注册到多路复用器上
底层:调用linux内核函数epoll_ctl进行事件绑定
涉及操作系统中断请求
底层:调用linux函数epoll_wait等待epoll实例上的事件
selector.select() //阻塞等待需要处理的事件发生
epoll
总结
redis
nginx
实例
NIO
AIO方式适用于连接数目多且连接比较长(重操作)的架构,JDK7 开始支持
AIO
IO模型
为什么Netty使用NIO而不是AIO?
目前使用4.x版本,5.x版本已经弃用
io.netty/netty‐all/4.1.35.Final
maven依赖
BossGroup和WorkerGroup类型都是NioEventLoopGroup
关键:selector底层对应的就是Nio的epoll模型
每个worker NIOEventLoop处理NioSocketChannel业务时,会使用 pipeline (管道),管道中维护了很多 handler处理器用来处理 channel 中的数据
Netty线程模型
ByteBuf详解
Channel
ChannelPipeline
ChannelHandler
组件
StringEncoderStringDecoder
ObjectEncoderObjectDecoder
netty内部
protostuff
自定义编码解码器
编码解码器
消息定长度,传输的数据大小固定长度,例如每段的长度固定为100字节,如果不够空位补空格
在数据包尾部添加特殊分隔符,比如下划线,中划线等,这种方法简单易行,但选择分隔符的时候一定要注意每条数据的内部一定不能出现分隔符。
发送长度:发送每条数据的时候,将数据的长度一并发送,比如可以选择每条数据的前4位是数据的长度,应用层处理时可以根据长度来判断每条数据的开始和结束。
解决方案
LineBasedFrameDecoder (回车换行分包)
DelimiterBasedFrameDecoder(特殊分隔符分包)
FixedLengthFrameDecoder(固定长度报文来分包)
netty内部方案
粘包拆包
注:这三个参数默认的时间单位是秒
IdleStateHandler
心跳检测机制
给ChannelFuture加一个监听器
客户端启动时连接失败,需要重连
需要再客户端的channelInactive中加入重连
连接中断开,客户端重连
自动重连
netty
netty详解
Netty
0 条评论
回复 删除
下一页