gpt4 book ai didi

c# - TcpClient 未正确接收数据

转载 作者:行者123 更新时间:2023-11-30 20:10:17 25 4
gpt4 key购买 nike

我有一个客户端-服务器程序。

我正在发送这样的数据:

private void Sender(string s,TcpClient sock)
{
try
{
byte[] buffer = Encoding.UTF8.GetBytes(s);
sock.Client.Send(buffer);
}catch{}
}

在客户端接收这样的:

byte[] buffer = new byte[PacketSize];
int size = client.Client.Receive(buffer);
String request = Encoding.UTF8.GetString(buffer, 0, size);

问题是数据并不总是被完全接收,有时它只是我发送的数据的一部分。 PacketSize 是 10240,比我发送的字节数还多。我还在两侧设置了 SendBufferSize 和 ReceiveBufferSize。

最糟糕的是有时数据会被完全接收!

可能是什么问题?

最佳答案

TcpClient.Receive 返回的size 值与您发送的缓冲字符串的长度不同。这是因为无法保证在调用 Receive 时您将取回通过 Send 调用发送的所有数据。这种行为是 TCP 工作方式所固有的(它是一种基于流的数据协议(protocol),而不是基于消息的数据协议(protocol))。

您无法通过使用更大的缓冲区来解决问题,因为您提供的缓冲区只能限制 Receive 返回的数据量。即使您提供了 1MB 的缓冲区并且有 1MB 的数据要读取,Receive 也可以合法地返回任意数量的字节(即使只有 1 个字节)。

您需要做的是确保在调用 Encoding.GetString 之前已缓冲所有数据。为此,您首先需要知道有多少数据。所以最起码,你需要在发送的时候写上字符串字节的长度:

  byte[] buffer = Encoding.UTF8.GetBytes(s);
byte[] length = BitConverter.GetBytes(buffer.Length);
sock.Client.Send(length);
sock.Client.Send(buffer);

接收时,您将首先读取长度(已知固定大小:4 字节),然后开始在临时缓冲区中缓冲其余数据,直到您有 length 字节(这可能需要任意数量的 Receive 调用,因此您需要一个 while 循环)。只有这样,您才能调用 Encoding.GetString 并取回原始字符串。

对您观察到的行为的解释:

即使操作系统的网络堆栈几乎没有任何保证,在实践中它通常会通过一次 Receive 调用为您提供一个 TCP 数据包带来的数据。由于 TCP 的 MTU(最大数据包大小)允许大约 1500 字节的有效负载,只要字符串小于此大小,原始代码就可以正常工作。不仅如此,它将被分成多个数据包,然后一个 Receive 将仅返回部分数据。

关于c# - TcpClient 未正确接收数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5283426/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com