netty原理详解

本文详细介绍了Netty框架的原理与应用,包括NIO客户端和服务端的创建步骤,展示了Netty在处理网络通信中的优势,如API简单、功能强大、性能优秀等。文章还提供了Netty的入门指南,通过DISCARD服务、ECHO服务和TIME服务的实现,帮助读者快速掌握Netty的使用。最后,探讨了如何处理流数据传输中的问题,以及如何用POJO代替ByteBuf以提高代码可维护性。
摘要由CSDN通过智能技术生成

 NIO客户端序列图

步骤一:打开SocketChannel,绑定客户端本地地址(可选,默认系统会随机分配一个可用的本地地址),示例代码如下:

1 SocketChannel clientChannel = SocketChannel.open();

步骤二:设置SocketChannel为非阻塞模式,同时设置客户端连接的TCP参数,示例代码如下:

1 clientChannel.configureBlocking(false);
2 socket.setReuseAddress(true);
3 socket.setReceiveBufferSize(BUFFER_SIZE);
4 socket.setSendBufferSize(BUFFER_SIZE);

步骤三:异步连接服务端,示例代码如下:

1 boolean connected = clientChannel.connect(new InetSocketAddress(“ip”,port));

步骤四:判断是否连接成功,如果连接成功,则直接注册读状态位到多路复用器中,如果当前没有连接成功(异步连接,返回false,说明客户端已经发送sync包,服务端没有返回ack包,物理链路还没有建立),示例代码如下:

1 if (connected)
2 {
3     clientChannel.register( selector, SelectionKey.OP_READ, ioHandler);
4 }
5 else
6 {
7     clientChannel.register( selector, SelectionKey.OP_CONNECT, ioHandler);
8 }

步骤五:向Reactor线程的多路复用器注册OP_CONNECT状态位,监听服务端的TCP ACK应答,示例代码如下:

1 clientChannel.register( selector, SelectionKey.OP_CONNECT, ioHandler);

步骤六:创建Reactor线程,创建多路复用器并启动线程,代码如下:

1 Selector selector = Selector.open();
2 New Thread(new ReactorTask()).start();

步骤七:多路复用器在线程run方法的无限循环体内轮询准备就绪的Key,代码如下:

1 int num = selector.select();
2 Set selectedKeys = selector.selectedKeys();
3 Iterator it = selectedKeys.iterator();
4 while (it.hasNext()) {
5 if (key.isConnectable())
6   //handlerConnect();
7 }

步骤九:判断连接结果,如果连接成功,注册读事件到多路复用器,示例代码如下:

1 if (channel.finishConnect())
2   registerRead();

步骤十:注册读事件到多路复用器:

1 clientChannel.register( selector, SelectionKey.OP_READ, ioHandler);

步骤十一:异步读客户端请求消息到缓冲区,示例代码如下:

1 int  readNumber =  channel.read(receivedBuffer);

步骤十二:对ByteBuffer进行编解码,如果有半包消息接收缓冲区Reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排,示例代码如下:

01 Object message = null;
02 while(buffer.hasRemain())
03 {
04        byteBuffer.mark();
05        Object message = decode(byteBuffer);
06        if (message == null)
07        {
08           byteBuffer.reset();
09           break;
10        }
11        messageList.add(message );
12 }
13 if (!byteBuffer.hasRemain())
14 byteBuffer.clear();
15 else
16     byteBuffer.compact();
17 if (messageList != null & !messageList.isEmpty())
18 {
19 for(Object messageE : messageList)
20    handlerTask(messageE);
21 }

步骤十三:将POJO对象encode成ByteBuffer,调用SocketChannel的异步write接口,将消息异步发送给客户端,示例代码如下:

1 socketChannel.write(buffer);

通过序列图和关键代码的解说,相信大家对创建NIO客户端程序有了一个初步的了解,下面,就跟随着我们的脚步继续看看如果使用NIO改造之前的时间服务器客户端TimeClient。

1

服务端序列图

步骤一:打开ServerSocketChannel,用于监听客户端的连接,它是所有客户端连接的父管道,代码示例如下:

1 ServerSocketChannel acceptorSvr = ServerSocketChannel.open();

步骤二:绑定监听端口,设置连接为非阻塞模式,示例代码如下:

1 acceptorSvr.socket().bind(new InetSocketAddress(InetAddress.getByName(“IP”), port));
2 acceptorSvr.configureBlocking(false);

步骤三:创建Reactor线程,创建多路复用器并启动线程,代码如下:

1 Selector selector = Selector.open();
2 New Thread(new ReactorTask()).start();

步骤四:将ServerSocketChannel注册到Reactor线程的多路复用器Selector上,监听ACCEPT事件,代码如下:

1 SelectionKey key = acceptorSvr.register( selector, SelectionKey.OP_ACCEPT, ioHandler);

步骤五:多路复用器在线程run方法的无限循环体内轮询准备就绪的Key,代码如下:

1 int num = selector.select();
2 Set selectedKeys = selector.selectedKeys();
3 Iterator it = selectedKeys.iterator();
4 while (it.hasNext()) {
5      SelectionKey key = (SelectionKey)it.next();
6      // ... deal with I/O event ...
7 }

步骤六:多路复用器监听到有新的客户端接入,处理新的接入请求,完成TCP三次握手,建立物理链路,代码示例如下:

1 SocketChannel channel = svrChannel.accept();

步骤七:设置客户端链路为非阻塞模式,示例代码如下:

1 channel.configureBlocking(false);
2 channel.socket().setReuseAddress(true);

步骤八:将新接入的客户端连接注册到Reactor线程的多路复用器上,监听读操作,用来读取客户端发送的网络消息,代码如下:

1 SelectionKey key = socketChannel.register( selector, SelectionKey.OP_READ, ioHandler);

步骤九:异步读取客户端请求消息到缓冲区,示例代码如下:

1 int  readNumber =  channel.read(receivedBuffer);

步骤十:对ByteBuffer进行编解码,如果有半包消息指针reset,继续读取后续的报文,将解码成功的消息封装成Task,投递到业务线程池中,进行业务逻辑编排,示例代码如下:

01 Object message = null;
02 while(buffer.hasRemain())
03 {
04        byteBuffer.mark();
05        Object message = decode(byteBuffer);
06        if (message == null)
07        {
08           byteBuffer.reset();
09           break;
10        }
11        messageList.add(message );
12 }
13 if (!byteBuffer.hasRemain())
14 byteBuffer.clear();
15 else
16     
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值