Netty服务端实现

Netty服务端实现教程

服务器端的实现,需要首先将业务处理的编解码和业务的 handler 实现出来,如果是 TCP 请求,需要处理粘包和拆包问题,然后将 bytebuf 对象转换成我们处理的业务对象。也要自定义 handler 对具体的业务逻辑进行处理。

Netty服务端编解码组织和实现

编码和解码是一个成对出现的逻辑,有编码就有解码。如果是 TCP 请求,就会需要考虑 TCP 的粘包和半包问题。然后将 netty 中的 bytebuf 对象转换成我们需要的业务处理对象。具体的请求路径图如下:

05 服务端编解码组织实现.png

在编码习惯中,我们喜欢对粘包拆包处理的编解码以 FrameDecoder/FrameEncoder 结尾,对具体的业务数据转换处理喜欢以 ProtocolDecoder/ProtocolEncoder 结尾。编码和解码是成对出现的,然后我们会执行我们自定义的 Handler 来处理自己的业务逻辑。

代码

整体代码结构如下:

06 服务端代码结构.png

粘包拆包编解码

OrderFrameDecoder解码

package io.netty.codec; import io.netty.handler.codec.LengthFieldBasedFrameDecoder; /** * @author 嗨客网 * @description */ public class OrderFrameDecoder extends LengthFieldBasedFrameDecoder { /** * 得到没有粘包和半包的 bytebuf */ public OrderFrameDecoder() { super(Integer.MAX_VALUE, 0, 2, 0, 2); } }

OrderFrameEncoder编码

package io.netty.codec; import io.netty.handler.codec.LengthFieldPrepender; /** * @author 嗨客网 * @description */ public class OrderFrameEncoder extends LengthFieldPrepender { /** * 得到没有粘包和半包的 bytebuf */ public OrderFrameEncoder() { super(2); } }

具体数据编解码

OrderProtocolDecoder解码器

package io.netty.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.common.RequestMessage; import io.netty.handler.codec.MessageToMessageDecoder; import java.util.List; /** * @author 嗨客网 * @description 二次解码器 */ public class OrderProtocolDecoder extends MessageToMessageDecoder<ByteBuf> { /** * 把 Bytebuf 对象转换成 requestmessage 对象 * * @param ctx * @param msg * @param out * @throws Exception */ @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception { RequestMessage requestMessage = new RequestMessage(); requestMessage.decode(msg); out.add(requestMessage); } }

OrderProtocolEncoder编码器

package io.netty.codec; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.common.ResponseMessage; import io.netty.handler.codec.MessageToMessageEncoder; import java.util.List; /** * @author 嗨客网 * @description 二次解码器 */ public class OrderProtocolEncoder extends MessageToMessageEncoder<ResponseMessage> { @Override protected void encode(ChannelHandlerContext ctx, ResponseMessage responseMessage, List<Object> out) throws Exception { ByteBuf buffer = ctx.alloc().buffer(); responseMessage.encode(buffer); out.add(buffer); } }

具体处理Handler

package io.netty.handler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.common.Operation; import io.netty.common.OperationResult; import io.netty.common.RequestMessage; import io.netty.common.ResponseMessage; /** * @author 嗨客网 * @description 服务端处理handler */ public class OrderServerProcessHandler extends SimpleChannelInboundHandler<RequestMessage> { @Override protected void channelRead0(ChannelHandlerContext ctx, RequestMessage msg) throws Exception { Operation operation = msg.getMessageBody(); OperationResult operationResult = operation.execute(); ResponseMessage responseMessage = new ResponseMessage(); responseMessage.setMessageHeader(msg.getMessageHeader()); responseMessage.setMessageBody(operationResult); ctx.writeAndFlush(responseMessage); } }

组织编解码器和handler

package io.netty.server; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.codec.OrderFrameDecoder; import io.netty.codec.OrderFrameEncoder; import io.netty.codec.OrderProtocolDecoder; import io.netty.codec.OrderProtocolEncoder; import io.netty.handler.OrderServerProcessHandler; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; /** * @author haicoder * @description */ public class Server { public static void main(String[] args) throws Exception { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); //设置日志级别 serverBootstrap.handler(new LoggingHandler(LogLevel.INFO)); serverBootstrap.group(new NioEventLoopGroup()); //处理具体逻辑是 childHandler 来处理的 serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new OrderFrameDecoder()); pipeline.addLast(new OrderFrameEncoder()); pipeline.addLast(new OrderProtocolEncoder()); pipeline.addLast(new OrderProtocolDecoder()); pipeline.addLast(new LoggingHandler(LogLevel.INFO)); pipeline.addLast(new OrderServerProcessHandler()); } }); ChannelFuture channelFuture = serverBootstrap.bind(8090).sync(); channelFuture.channel().closeFuture().get(); } }

Netty服务端实现总结

本章我们对服务端的流程有了一个总体的讲解,它需要有编解码和具体 handler 处理器。我们也了解了 netty 这边定义编解码时候的代码习惯。