和服务端实现类似,Netty 客户端也需要实现相应的编解码逻辑,只不过具体的业务处理逻辑,客户端不需要关心,因为已经在服务端进行处理了。
对应的编解码请求流程如下图:
客户端编解码的代码结构图如下:
package io.netty.client.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.common.RequestMessage;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.util.List;
/**
* @author 嗨客网
* @description 二次解码器
*/
public class OrderProtocolEncoder extends MessageToMessageEncoder<RequestMessage> {
@Override
protected void encode(ChannelHandlerContext ctx, RequestMessage requestMessage, List<Object> out) throws Exception {
ByteBuf buffer = ctx.alloc().buffer();
requestMessage.encode(buffer);
out.add(buffer);
}
}
package io.netty.client.codec;
import io.netty.handler.codec.LengthFieldPrepender;
/**
* @author 嗨客网
* @description
*/
public class OrderFrameEncoder extends LengthFieldPrepender {
/**
* 得到没有粘包和半包的 bytebuf
*/
public OrderFrameEncoder() {
super(2);
}
}
package io.netty.client.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.client.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.common.ResponseMessage;
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 {
ResponseMessage responseMessage = new ResponseMessage();
responseMessage.decode(msg);
out.add(responseMessage);
}
}
package io.netty.client;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
import io.netty.client.codec.OrderFrameDecoder;
import io.netty.client.codec.OrderFrameEncoder;
import io.netty.client.codec.OrderProtocolDecoder;
import io.netty.client.codec.OrderProtocolEncoder;
import io.netty.common.RequestMessage;
import io.netty.common.order.OrderOperation;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.IdUtil;
/**
* @author 嗨客网
* @description 组织编解码
*/
public class Client {
public static void main(String[] args) throws Exception {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(new NioEventLoopGroup());
//处理具体逻辑是 childHandler 来处理的
bootstrap.handler(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));
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8090);
channelFuture.sync();
RequestMessage requestMessage = new RequestMessage(IdUtil.nextId(), new OrderOperation(1001, "小鸡炖蘑菇"));
channelFuture.channel().writeAndFlush(requestMessage);
channelFuture.channel().closeFuture().get();
}
}
本章节,我们定义了客户端编解码器,并且定义了一个 client 类将编解码器进行了组织连接。这样就可以将客户端和服务端进行通信了。