环境
服务器用的是 JAVA
,网络用的库是 Netty
。客户端用的 UnityGameFramework
。准备协议用 Protobuf
。
协议结构
客户端向服务器发送的数据帧结构
帧长度(4 byte, 不包括自己这四个) | 消息ID (4 byte) | 数据长度 (4 byte) | 数据
服务器解析代码
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.option(ChannelOption.SO_BACKLOG, 1000); // default 50
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4))
.childHandler(new DecodeFrame())
.childHandler(this.channelChannelInitializer);
DecodeFrame
是自定义类来解析 消息ID (4 byte) | 数据长度 (4 byte) | 数据
结构的, 和问题无关,略过了。
客户端代码
在 NetworkChannelHelper
中的的 Serialize
函数写入数据的部分代码,
byte[] bytes = sayHello.ToByteArray();
int packetLength = 8 + bytes.Length;
m_CachedStream.SetLength(0); // 这里的代码
m_CachedStream.Position = 0;
m_CachedStream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(packetLength)), 0 , 4);
m_CachedStream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((int)1)), 0, 4);
m_CachedStream.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(bytes.Length)), 0, 4);
m_CachedStream.Write(bytes, 0, bytes.Length);
m_CachedStream.WriteTo(destination);
之前每次写入新的消息的时候,没有下面的代码
m_CachedStream.SetLength(0);
导致了问题。
比如,第一个消息全部是 500 byte(包括帧长度),第二个消息 250 byte,由于没有重新设置长度为0, 所以第二次发送的时候,总共发送了 500 byte(包括第一个消息的 后面 250 个 byte)。服务器能够正常解析第二个消息,但是会在缓冲区中留下第一帧的后面的 250 个byte。所以在客户端发送第三个消息的时候,基本都是报错了。识别不了数据。