解析可变大小的数据包

时间:2017-07-01 14:23:10

标签: c# uwp network-protocols

我正在进行多人游戏,而且我从解析连接数据包的方式出现问题。当我调试游戏时,它以较低的性能运行并且收到数据包,而当我没有收到数据包时,数据包没有被完全接收并且ParsePacket方法也没有被调用。

我的数据包结构如下:

  

2字节短命令,2字节短有效载荷大小,(可选)有效载荷字节

IInputStream inputStream = null;
DataReader dataReader = null;

byte[] data = new byte[1024];
IBuffer buffer = data.AsBuffer();

try
{
    inputStream = StreamSocket.InputStream;

    dataReader = DataReader.FromBuffer(buffer);
    dataReader.InputStreamOptions = InputStreamOptions.Partial;
    dataReader.ByteOrder = ByteOrder.LittleEndian;

    while (connected)
    {
        await inputStream.ReadAsync(buffer, 1024, InputStreamOptions.Partial);
        Debug.WriteLine("Buffer " + buffer.Length);

        if (buffer.Length >= PacketHeaderSize)
        {
            short command = dataReader.ReadInt16();
            short payloadSize = dataReader.ReadInt16();
            byte[] payload = null;

            if (payloadSize == 0)
            {
                UpdateBuffer(buffer, (uint)(PacketHeaderSize + payloadSize));

                Packet packet = new Packet(command, payloadSize, payload);
                ParsePacket(packet);
            }
            else if (payloadSize > 0)
            {
                if (buffer.Length >= (PacketHeaderSize + payloadSize))
                {
                    payload = new byte[payloadSize];
                    dataReader.ReadBytes(payload);

                    UpdateBuffer(buffer, (uint)(PacketHeaderSize + payloadSize));

                    Packet packet = new Packet(command, payloadSize, payload);
                    ParsePacket(packet);
                }
            }
        }
    }
}
catch (Exception e) {
    // ...
}

private void UpdateBuffer(IBuffer buffer, uint bytesRead)
{
    if (buffer.Length > bytesRead)
    {
        byte[] bufferBytes = new byte[buffer.Length - bytesRead];
        System.Buffer.BlockCopy(buffer.ToArray(), (int)bytesRead, bufferBytes, 0, (int)(buffer.Length - bytesRead));
        buffer = bufferBytes.AsBuffer();
    }
    else
    {
        byte[] bufferBytes = new byte[1024];
        buffer = bufferBytes.AsBuffer();
    }
}

我做错了什么?

1 个答案:

答案 0 :(得分:0)

使这项工作得以修复:

  • 将重要变量放在解析数据包循环之外,因为下次我们需要解析另一个数据包时需要这个值。
  • 如果收到不完整的应用或游戏数据包,请阅读一次数据包标题。
  • 仅加载 我们需要的字节
  • 使用 UnconsumedBufferLength 完全接收后,读取标头和有效负载。

代码:

short command = 0;
short payloadSize = 0;
byte[] payload = null;

bool packetHeaderRead = false;

while (connected)
{
    if (!packetHeaderRead)
    {
        if (dataReader.UnconsumedBufferLength < PacketHeaderSize)
        {
            int headerBytesLeft = PacketHeaderSize - (int)dataReader.UnconsumedBufferLength;

            if (headerBytesLeft > 0)
            {
                await dataReader.LoadAsync((uint)headerBytesLeft);
                continue;
            }
        }
        else
        {
            command = dataReader.ReadInt16();
            payloadSize = dataReader.ReadInt16();
            packetHeaderRead = true;
            continue;
        }
    }
    else
    {
        int payloadBytesLeft = payloadSize - (int)dataReader.UnconsumedBufferLength;

        if (payloadBytesLeft > 0)
        {
            await dataReader.LoadAsync((uint)payloadBytesLeft);
        }

        if (payloadSize == 0)
        {
            Packet packet = new Packet(command, payloadSize, payload);
            ParsePacket(packet);

            packetHeaderRead = false;
        }
        else if (dataReader.UnconsumedBufferLength >= payloadSize)
        {
            payload = new byte[payloadSize];
            dataReader.ReadBytes(payload);

            Packet packet = new Packet(command, payloadSize, payload);
            ParsePacket(packet);

            packetHeaderRead = false;
        }
    }
}