嘿,我在使用自定义二进制协议分离数据包时遇到问题。 目前,服务器端代码如下所示。
public void HandleConnection(object state)
{
TcpClient client = threadListener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
byte[] data = new byte[4096];
while (true)
{
int recvCount = stream.Read(data, 0, data.Length);
if (recvCount == 0) break;
LogManager.Debug(Utility.ToHexDump(data, 0, recvCount));
//processPacket(new MemoryStream(data, 0, recvCount));
}
LogManager.Debug("Client disconnected");
client.Close();
Dispose();
}
我一直在观看数据包的十六进制转储,有时整个数据包都是一次性的,比方说全部是20个字节。其他时候它是碎片化的,我如何缓冲这些数据,以便能够正确地将它传递给我的processPacket()方法。我只是尝试使用单字节操作码头,我应该添加像(ushort)contentLength这样的东西吗?我正在尝试使协议尽可能轻量级,并且该系统不会发送非常大的数据包(<128字节)。
我正在测试的客户端代码如下。
public void auth(string user, string password)
{
using (TcpClient client = new TcpClient())
{
client.Connect(IPAddress.Parse("127.0.0.1"), 9032);
NetworkStream networkStream = client.GetStream();
using (BinaryWriter writer = new BinaryWriter(networkStream))
{
writer.Write((byte)0); //opcode
writer.Write(user.ToUpper());
writer.Write(password.ToUpper());
writer.Write(SanitizationMgr.Verify()); //App hash
writer.Write(Program.Seed);
}
}
}
我不确定这可能是什么搞乱了,二进制协议似乎没有太多关于网络的信息,特别是涉及C#的地方。任何评论都会有所帮助。 =)
解决这个,不确定它是否正确,但它似乎给我的处理程序正好他们需要的东西。
public void HandleConnection(object state)
{
TcpClient client = threadListener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
byte[] data = new byte[1024];
uint contentLength = 0;
var packet = new MemoryStream();
while (true)
{
int recvCount = stream.Read(data, 0, data.Length);
if (recvCount == 0) break;
if (contentLength == 0 && recvCount < headerSize)
{
LogManager.Error("Got incomplete header!");
Dispose();
}
if(contentLength == 0) //Get the payload length
contentLength = BitConverter.ToUInt16(data, 1);
packet.Write(data, (int) packet.Position, recvCount); //Buffer the data we got into our MemStream
if (packet.Length < contentLength + headerSize) //if it's not enough, continue trying to read
continue;
//We have a full packet, pass it on
//LogManager.Debug(Utility.ToHexDump(packet));
processPacket(packet);
//reset for next packet
contentLength = 0;
packet = new MemoryStream();
}
LogManager.Debug("Client disconnected");
client.Close();
Dispose();
}
答案 0 :(得分:3)
您应该将其视为流。不要依赖任何特定的分块行为。
您需要的数据量是否始终相同?如果没有,您应该更改协议(如果可以的话)以数据的逻辑“块”为前缀,以字节为单位。
在这种情况下,您在一方使用BinaryWriter
,因此将BinaryReader
附加到NetworkStream
返回的TcpClient.GetStream()
似乎是最简单的方法。如果你真的想一次捕获一个块的所有数据,你应该回到我的想法,用它的长度前缀数据。然后循环,直到你获得所有数据。
(确保你有足够的数据来读取长度!如果你的长度前缀是4个字节,你不想读取2个字节并错过接下来的2个......)