C#IInputStream缺少分​​段TCP包

时间:2017-01-11 18:37:52

标签: c# sockets tcp

我正在编写一个小型HttpServer,有时我遇到了丢失POST数据的问题。

通过使用Wireshark,我发现Header被分为two segments

Wireshark Reassembled TCP Segments

我只得到第一个段(636个字节),第二个段(在这种情况下为POST数据)完全丢失。

这是相关的C#代码

string requestHeaderString = "";
StreamSocket socketStream = args.Socket;

IInputStream inputStream = socketStream.InputStream;
byte[] data = new byte[BufferSize];
IBuffer buffer = data.AsBuffer();

try
{
    await inputStream.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);

    // This is where things go missing, buffer.ToArray() should be 678 Bytes long, 
    // so Segment 1 (636 Bytes) and Segment 2 (42 Bytes) combined.
    // But is only 636 Bytes long, so just the first Segment?!
    requestHeaderString += Encoding.UTF8.GetString(buffer.ToArray());
}
catch (Exception e)
{
    Debug.WriteLine("inputStream is not readable" + e.StackTrace);
    return;
}

此代码属于StreamSocketListener ConnectionReceived Event的一部分。

我是否需要手动重新组装TCP段,这不是系统TCP堆栈应该做的事情吗?

谢谢, 大卫

1 个答案:

答案 0 :(得分:2)

问题是系统TCP堆栈像处理任何其他流一样处理TCP流。你没有得到"消息"使用流,您只需获得一个字节流。

接收方无法确定何时发出消息"结束,下一个开始的地方,你没有告诉它如何。您必须在TCP之上实现message framing,然后在接收方必须重复调用Receive,直到您收到足够的字节来形成完整的消息(这将涉及使用返回的int从接收调用中查看处理的字节数。)

重要说明:如果您不知道您希望获得多少字节,例如,您正在使用'\0'分隔邮件进行邮件框架,则可能会收到一封邮件的结尾并在单个接收呼叫中开始下一个。你需要处理这种情况。

编辑:对不起,我跳过你读HTTP的事实。您必须遵循HTTP协议。你必须读入数据,直到你看到模式\r\n\r\n,一旦你得到它你必须解析标题并解码HTTP消息的内容部分中有多少数据然后重复调用读取,直到你已经读取了数字需要的字节。