TcpClient/Server NetworkStream正在跳过数据包
本文关键字:数据包 Server NetworkStream TcpClient | 更新日期: 2023-09-27 18:25:47
在我的程序中的某些时刻,从不同的线程到服务器的写入几乎是同时进行的。我注意到,当两者几乎立即发送时,其中一个永远不会到达服务器,尽管使用了TCP,应该确保收到数据包。
为了测试这一点,我只需一个接一个地发送1000个数据包,没有延迟:
NetworkStream stream = server.GetStream();
int i = 0;
while (i < 1000)
{
byte[] data = Encoding.Unicode.GetBytes(i.ToString() + "$");
stream.Write(data, 0, data.Length);
i++;
}
并接收:
bool LostConnection = false;
NetworkStream stream = client.GetStream()
while (ClientSocket.Connected && !LostConnection && !AppIsClosing)
{
try
{
byte[] ReceivedBytes = new byte[4096];
if (stream.Read(ReceivedBytes, 0, ReceivedBytes.Length) == 0)
{ LostConnection = true; break; }
string DataFromClient = Encoding.Unicode.GetString(ReceivedBytes);
if (DataFromClient.Contains("$"))
{
DataFromClient = DataFromClient.Substring(0, DataFromClient.IndexOf("$"));
Console.WriteLine(" >> " + DataFromClient);
}
}
catch { }
}
输出:
>> 0
>> 1
>> 20
>> 76
>> 108
>> 136
>> 163
>> 197
>> 220
>> 241
>> 276
>> 302
>> 330
>> 372
>> 373
>> 469
>> 507
>> 530
>> 560
>> 590
>> 628
>> 651
>> 683
>> 722
>> 747
>> 772
>> 803
>> 826
>> 861
>> 889
>> 913
>> 950
>> 980
是什么导致了这种现象?
附言:我也试过:
var result = stream.WriteAsync(data, 0, data.Length);
result.Wait();
运气不好。。。
更新:
好吧,我很笨。流包含所有其他堆积起来的文本,我只是用Substring(0, IndexOf("$"))
将其删除所以现在我只是用新行替换$,但后来我遇到了另一个问题。在800-900左右的某个地方,它再次从500开始计数,然后达到999。这是怎么回事?
重大建议,请阅读并理解此链接。您需要连同您的数据一起发送一些关于您正在发送的内容的元数据。比如你发送了多少字节。如果你发送"555$",那么你必须在这个前缀前说:我发送4个字节。您需要有一个能够理解这一点的监听器,并等待4个字节。
我在这里引用上面的链接
Okay, so let's think about the possible situations that
might occur with the data that the server receives in one receive operation:
- 在第一次接收操作中,接收的字节数少于前缀
- 在先前的一个或多个接收操作上具有前缀的接收部分之后,然后接收前缀的另一部分,但不接收所有这些
- 在之前的一次或多次接收操作中接收到部分前缀后,再接收前缀的其余部分,但仅限于此
- 在之前的一个或多个接收操作中接收到前缀的一部分后,我们将接收它的其余部分,以及消息的一部分
- 在之前的一个或多个接收操作中接收到部分前缀后,我们将接收其余前缀以及所有消息
- 接收前缀中的确切字节数,但仅限于此
- 在准确地接收到前一个或多个接收操作的前缀中的字节数后,我们将接收消息
- 在准确地接收到前一个或多个接收操作的前缀中的字节数之后,我们将接收所有消息
- 接收前缀的字节数加上消息的一部分,但不是全部消息
- 在之前的一个或多个接收操作中接收到前缀和消息的一部分后,我们将接收信息,但不是全部
- 在之前的一个或多个接收操作中接收到前缀和部分消息后,我们将接收消息
- 在第一个接收操作上接收前缀的字节数加上所有消息
最后一件事实际上是将要发生的最常见的事情。但所有上面的事情可以发生,而且确实会发生。如果两个客户端和服务器的缓冲区大小大于消息,则当同时运行客户端和服务器在同一台机器上,甚至在局域网上。但是TCP更重要在数据通过的互联网上不可预测多台机器。因此,您的代码需要允许所有这些可能性。
我认为问题出在这条线上
DataFromClient = DataFromClient.Substring(0, DataFromClient.IndexOf("$"));
您假设每次读取将获得1个字符串,但一次读取可能有许多可用字符串。您应该尝试使用split("$"),并将所有结果写入