服务器端的实现,需要首先将业务处理的编解码和业务的 handler 实现出来,如果是 TCP 请求,需要处理粘包和拆包问题,然后将 bytebuf 对象转换成我们处理的业务对象。也要自定义 handler 对具体的业务逻辑进行处理。
编码和解码是一个成对出现的逻辑,有编码就有解码。如果是 TCP 请求,就会需要考虑 TCP 的粘包和半包问题。然后将 netty 中的 bytebuf 对象转换成我们需要的业务处理对象。具体的请求路径图如下:
在编码习惯中,我们喜欢对粘包拆包处理的编解码以 FrameDecoder/FrameEncoder 结尾,对具体的业务数据转换处理喜欢以 ProtocolDecoder/ProtocolEncoder 结尾。编码和解码是成对出现的,然后我们会执行我们自定义的 Handler 来处理自己的业务逻辑。
整体代码结构如下:
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);
}
}
package io.netty.codec;
import io.netty.handler.codec.LengthFieldPrepender;
/**
* @author 嗨客网
* @description
*/
public class OrderFrameEncoder extends LengthFieldPrepender {
/**
* 得到没有粘包和半包的 bytebuf
*/
public OrderFrameEncoder() {
super(2);
}
}
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);
}
}
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);
}
}
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);
}
}
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();
}
}
本章我们对服务端的流程有了一个总体的讲解,它需要有编解码和具体 handler 处理器。我们也了解了 netty 这边定义编解码时候的代码习惯。