系列文章目录
16进制数据及解决半包和粘包
制定协议
协议分为head和body,其中head固定是4位,第一位暂时不代表任何意义,后期可以用来表示协议版本和是否压缩等。第二位表示要进行的动作,第三和第四位表示协议body的长度。
一、协议实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author Mr.Guo
* @date 2021/3/6 下午12:24
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Xa87Packet implements Serializable, Cloneable {
private int command;
private int length;
private byte[] body;
}
二、创建新的Encoder、Decoder
1.MessageEncoder
import cn.xa87.im.demo.packet.Xa87Packet;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/**
* @author Mr.Guo
* @date 2021/3/6 上午9:58
*/
public class MessageEncoder extends MessageToByteEncoder<Xa87Packet> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Xa87Packet xa87Packet, ByteBuf byteBuf) throws Exception {
byteBuf.writeByte(0x00);
byteBuf.writeByte(0x01);
byteBuf.writeShort(xa87Packet.getLength());
byteBuf.writeBytes(xa87Packet.getBody());
}
}
2.MessageDecoder
import cn.xa87.im.demo.packet.Xa87Packet;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
/**
* @author Mr.Guo
* @date 2021/3/6 上午9:58
*/
public class MessageDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
int readableLength = byteBuf.readableBytes();
if (readableLength < 1) {
return;
}
byteBuf.markReaderIndex();
byte firstByte = byteBuf.readByte();
byte actByte = byteBuf.readByte();
int bodyLength = byteBuf.readShort();
if (readableLength < bodyLength + 4) {
byteBuf.resetReaderIndex();
return;
}
byte[] body = new byte[bodyLength];
byteBuf.readBytes(body);
list.add(new Xa87Packet(actByte, bodyLength, body));
}
}
三、替换StringEncoder、StringDecoder
import cn.xa87.im.demo.coder.MessageDecoder;
import cn.xa87.im.demo.coder.MessageEncoder;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Mr.Guo
* @date 2021/3/4 下午4:53
*/
@Component
public class SocketServerInitializer extends ChannelInitializer<SocketChannel> {
@Autowired
private SocketMsgHandler socketMsgHandler;
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//添加对于读写大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
//对httpMessage进行聚合
pipeline.addLast(new HttpObjectAggregator(1024 * 64));
//pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
//pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast("decoder", new MessageDecoder());
pipeline.addLast("encoder", new MessageEncoder());
//自定义handler
pipeline.addLast(socketMsgHandler);
}
}
运行结果