套接字发送需要localhost目标的延迟

问题描述 投票:0回答:2

我目前正在研究一个C#服务器/客户端项目,并遇到了一个奇怪的问题,需要我一段时间来解决,但我对解决方案并不完全满意,或者更确切地说是为什么我需要它。基本上我发现将超过10千字节的tcp套接字消息发送到localhost目标需要1ms的时间延迟。

作为背景,我在一台机器上有一台服务器,许多客户端都连接到这台服务器并来回传递信息,这些信息似乎都运行正常。我也有服务器的本地客户端也连接。我遇到的问题是,当消息大小超过大约10千字节时,消息将无法通过。我只是注意到这一点,因为发送的大多数消息大小约为1-2千字节,但与服务器(localhost)连接在同一台机器上的客户端更像是一个管理客户端,因此发送/接收更多数据。

真正的问题是服务器(发送者)从发送数据的C#send命令返回true / success,但是,接收者只指示第一个chunk(如果我缓冲)或者什么都没有。所以我最终把wireshark打开并看到即使发送调用成功完成,也不会通过线路实际发送数据(记住这是在本地环回接口上)。

我试着玩我如何发送数据和尝试所有不同的调用(NetworkStream.Write / NetworkStream.WriteAsync / Socket.Send / Socket.SendAsync / Socket.BeginSend)以及缓冲数据或一次性发送它们。在我的循环中发送调用之间的时间延迟然后一切正常工作(我测试了1.5GB的数据流没有问题)之前,似乎没有任何区别。

我还发现任何低于1毫秒/ 10,000蜱的延迟会再次导致问题,我会通过这么多的发送呼叫工作,然后他们会再次停止。将TcpClient.NoDelay设置为true也似乎没有太大影响。

下面是我的发送代码的剪切作为一个例子,我尝试过的所有具有完全相同行为的不同发送命令。

// _client is an abstracted/based off a TcpClient object (the target)
byte[] dataBytes = Serializer.SerializeMessage(message); 
int    bytesSent = 0;

while (bytesSent < dataBytes.Length) {
   int bytesToSend = ((dataBytes.Length - bytesSent) < 8192) ? (dataBytes.Length - bytesSent) : 8192;
   //_client.Socket.Send(dataBytes, bytesSent, bytesToSend, SocketFlags.Partial);
   //_client.NetworkStream.Write(dataBytes, bytesSent, bytesToSend);
   //_client.Socket.BeginSend(dataBytes, bytesSent,bytesToSend,SocketFlags.None, ar => {int bytes = ((Socket)ar.AsyncState).EndSend(ar);}, _client.Socket);
   _ = _client.NetworkStream.WriteAsync(dataBytes, bytesSent, bytesToSend);

   bytesSent += bytesToSend;
   Thread.Sleep(TimeSpan.FromTicks(10000));
}

所以虽然现在这个工作正常,我的问题是为什么它甚至需要,从以前的经验我总是发现,如果你需要“延迟”有其他错误的东西。此外,没有延迟,没有任何错误输出,所有的调用报告他们成功发送了字节,但wireshark显示没有数据被传输。我唯一的想法是在库中检测到它是一个本地目标,并使用从我抽象的一些内部命名管道,缓冲区填满了某个地方?

我已经尝试搜索这样的任何问题超过一个星期,并且找不到任何明显的东西,所以任何见解都会非常感激。

c# sockets asynchronous networkstream
2个回答
0
投票

根据以往的经验,我总能找到你是否需要“延迟”还有其他错误。

Righto。在这里,我怀疑你假设套接字上的Read将返回一个完整的消息。

但TCP / IP是一种流协议,不包括任何消息概念。要直接成功使用TCP / IP,必须定义“消息成帧协议”,以便与远程主机通信预期的字节数。我没有看到你在消息之前写任何东西,所以我怀疑那是什么遗漏。

许多人使用的简单解决方案是始终在消息开头发送一个4字节的整数,表示将要发送的字节数。然后,读取器可以执行4字节读取,然后执行读取循环,直到读取预期的字节数。


0
投票

因此,问题变成了计算机本身(或者更确切地说是我们的许多开发盒)上的某些问题,这些问题影响了在localhost绑定上托管/连接的任何服务。这包括许多网络服务,如果托管是本地的,甚至包括IISExpress和IIS。这导致任何大小超过10千字节的数据从未被发送/接收。

经过几天试图找出影响localhost连接的因素后,我们最终重建了我们的开发盒,问题现在已经消失(尽管我们仍然不知道为什么/导致问题的原因)。

© www.soinside.com 2019 - 2024. All rights reserved.