框架似乎不起作用......当两个客户端同时连接时,我会从两者中获得相同的数据。
当客户端的通道变为活动状态时,它会发送一个HandshakeRequest,它几乎只是一个包含服务器主机名的字符串,以允许服务器从数据库中获取有关它的一些详细信息。
@Override
public void channelActive(ChannelHandlerContext context) {
HandshakeRequest packet = new HandshakeRequest();
packet.setHostname(Client.HOSTNAME);
context.writeAndFlush(packet);
}
HandshakeRequest:
@Getter @Setter private String hostname;
public HandshakeRequest() {
super(Packet.HANDSHAKE_REQUEST);
}
@Override
public void write(ByteBuf buf) {
writeString(hostname, buf);
}
@Override
public void read(ByteBuf buf) {
hostname = readString(buf);
}
初始化器:
@Override
public void initChannel(SocketChannel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new PacketEncoder());
pipeline.addLast(new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, 0, 2, 0, 2));
pipeline.addLast(new PacketDecoder());
pipeline.addLast(new ClientHandler(client));
}
PacketEncoder:
@Override
protected void encode(ChannelHandlerContext context, DefinedPacket packet, ByteBuf buf) {
buf.writeInt(packet.packet().getId());
packet.write(buf);
}
PacketDecoder:
@Override
protected void decode(ChannelHandlerContext context, ByteBuf in, List<Object> out) {
int id = in.readInt();
DefinedPacket packet = Packet.getTypeById(id).getPacket();
if(packet != null) {
packet.read(in);
packet.setId(id);
out.add(packet);
} else {
in.skipBytes(in.readableBytes());
}
}
DefinedPacket(这是所有数据包扩展的抽象类):
public static void writeString(String s, ByteBuf buf) {
if(s.length() > Short.MAX_VALUE) {
throw new OverflowPacketException(String.format("Cannot send string longer than Short.MAX_VALUE (got %s characters)", s.length()));
}
byte[] b = s.getBytes(Charsets.UTF_8);
writeVarInt(b.length, buf);
buf.writeBytes(b);
}
public static String readString(ByteBuf buf) {
int len = readVarInt(buf);
if(len > Short.MAX_VALUE) {
throw new OverflowPacketException(String.format("Cannot receive string longer than Short.MAX_VALUE (got %s characters)", len));
}
byte[] b = new byte[len];
buf.readBytes(b);
return new String(b, Charsets.UTF_8);
}
public static int readVarInt(ByteBuf input) {
return readVarInt(input, 5);
}
public static int readVarInt(ByteBuf input, int maxBytes) {
int out = 0;
int bytes = 0;
byte in;
while(true) {
in = input.readByte();
out |= (in & 0x7F) << (bytes++ * 7);
if(bytes > maxBytes) {
throw new RuntimeException("VarInt too big");
}
if((in & 0x80) != 0x80) {
break;
}
}
return out;
}
public static void writeVarInt(int value, ByteBuf output) {
int part;
while(true) {
part = value & 0x7F;
value >>>= 7;
if(value != 0) {
part |= 0x80;
}
output.writeByte(part);
if(value == 0) {
break;
}
}
}
private final Packet type;
@Getter @Setter private int id;
public DefinedPacket(Packet type) {
this.type = type;
}
public Packet packet() {
return type;
}
public abstract void write(ByteBuf buf);
public abstract void read(ByteBuf buf);
答案 0 :(得分:0)
你能为
提供全班吗?request
...
你将@Override
public void initChannel(SocketChannel channel) {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new PacketEncoder());
pipeline.addLast(new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, 0, 2, 0, 2));
pipeline.addLast(new PacketDecoder());
pipeline.addLast(new ClientHandler(client));
}
传递给ClientHandler的构造函数的位置是什么?
答案 1 :(得分:0)
我已经解决了这个问题。事实证明,在解码后处理新的数据包实例的方式是一个问题(为同一个数据包的每个实例重用相同的对象)。这只是一个非常愚蠢的错误:P