【问题标题】:Async TCP System.Net.Socket send (Begin/End Send) not actually sending anything异步 TCP System.Net.Socket 发送(开始/结束发送)实际上并未发送任何内容
【发布时间】:2011-09-07 18:58:37
【问题描述】:

背景:

我在一台机器上运行 TCP 服务器,多个客户端在通过 TCP 连接的不同机器上,我正在使用 Wireshark 监控网络流量,以及从我的服务器应用程序中进行日志记录,并通过 System.Diagnostics 跟踪侦听器System.Net.Sockets 处于详细模式。

问题:

由于一些意外断开连接提示检查我的日志,我看到一些非常奇怪的行为。根据服务器应用程序日志和 System.Diagnostic 输出日志,我的服务器正在使用开始/结束发送向客户端发送一个 4 字节数据包。 BeginSend 完成,EndSend 也完成,表示它成功发送了 4 字节数据包。

但是,当我查看 Wireshark 日志时,该数据包从未出现过。我在服务器机器上运行 Wireshark,所以数据包应该没有理由出现在我的服务器和跟踪日志中,但不会出现在同一台机器上的 Wireshark 日志中。

此外,在所谓的成功发送数据包后不久(约 30 秒后)发生意外断开连接,这是由我的服务器的 EndReceive 方法上的 SocketException 引起的。但是在尝试从服务器发送之间的时间段内,服务器正在确认从客户端接收到的数据包,所以我知道连接仍然处于活动状态。

有没有人有类似的经历,或者知道一个错误或可能导致这种情况的东西?

我不想认为这是在套接字级别发生的,TCP 说我的数据包在它甚至从未到达网络时发送,这意味着我不能依赖 TCP 作为可靠的传输(这当然是 TCP 的重点)。

日志样本

来自我的服务器应用程序:

    2011-09-07 10:41:38,812 Attempting to send Packet (BeginSend - 4 bytes)
    2011-09-07 10:41:38,812 Sent Packet (EndSend - 4 bytes)

来自 System.Diagnostics 跟踪日志:

System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::BeginSend()
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] Data from Socket#19699911::PostCompletion
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [0980] 00000000 : 02 04 00 00                                     : ....
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Socket#19699911::EndSend(OverlappedAsyncResult#44209720)
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::EndSend()   -> 4#4
    DateTime=2011-09-07T17:41:38.8125000Z
System.Net.Sockets Verbose: 0 : [4376] Exiting Socket#19699911::BeginSend()     -> OverlappedAsyncResult#44209720
    DateTime=2011-09-07T17:41:38.8125000Z

我也会粘贴 Wireshark 日志,但当时该设备的接口上基本上没有任何注册,除了来自客户端的数据包和来自服务器的相应确认。

编辑: 根据要求,这是发送的代码(由于空间和其他原因而缩短)。很简单,没有太多可能出错的地方。

在我的 BeginSend 方法中:

socket.BeginSend(data, 0, data.Length, SocketFlags.None, EndSend, state);

在我的 EndSend 方法中:

bytesSent = socket.EndSend(ar);

注意:正如他们所说,这不是我第一次参加牛仔竞技表演...过去 15 年来我一直在使用 TCP 套接字编写服务器和客户端,以前从未经历过。

另外,我使用的 .NET 版本是 4.0...如果有任何相关性的话。

救命!

【问题讨论】:

  • 您可以在帖子中添加相关的客户端和服务器代码吗?可能代码有错误。
  • 添加了一些代码...但实际上并没有什么特别的。这是一个简单的 BeginSend 和 EndSend...您可以从 MSDN 或其他地方获取任何示例代码并重现我所看到的。
  • 也许我对 TCP 如何在 .NET 平台上工作的理解不正确......当消息已传输到接收方并得到接收方确认后,Socket.EndSend 调用是否会成功返回?或者当 .NET 将消息成功发送到网络接口时,EndSend 是否会成功?如果是后者,网络适配器故障可能会解释我所看到的情况。
  • 客户端看到那个 4 字节的传输了吗?您的帖子暗示客户端和服务器之间的对话无论如何都会继续进行。
  • 另外,SocketException 提供了哪些详细信息?信息? Error code?

标签: c# sockets diagnostics


【解决方案1】:

我在 .NET 中使用套接字编程时遇到的一个问题与垃圾收集有关。我的代码是在我的方法中创建一个套接字并分配给一个局部变量,而不是分配给一个成员变量。然后套接字被垃圾收集,导致SocketException。显然,执行 BeginSend 不足以保存对该套接字的引用。

将套接字移动到成员变量为我解决了这个问题。希望这与您遇到的问题有关。

【讨论】:

  • 不幸的是,这不是问题......但评论仍然与套接字编程相关。任何跨越多个线程或方法的套接字交互都应该引用一个不会像那样被收集的变量。
【解决方案2】:

我不想认为这是在套接字级别发生的, TCP 在哪里说我的数据包是在它从未发送的时候发送的 到电线上,这意味着我不能依赖 TCP 作为 可靠的传输(这当然是 TCP 的重点)。

这个说法不正确。仅仅因为您成功写入套接字并不意味着数据已被客户端接收甚至离开您的机器。这只是意味着它已成功写入内部 TCP/IP 缓冲区。 TCP/IP 将以它认为合适的尽可能多或尽可能少的块/帧发送该数据。如果您发送的数据很小,则尤其如此,TCP/IP 将延迟尝试将其他数据聚合到帧中。

如果您在 Wireshark 中没有看到它,那么您可能没有在正确的接口上侦听、设置了过滤器,或者某种防火墙阻止了您发送数据。查看任何现有的防病毒或其他分层服务提供商,看看谁可以进入那里。

【讨论】:

  • 我在这个界面上看到了我所有的其他数据,事实上,无论如何只有一个界面可用。我认为我看到的问题必须存在于我的应用程序下面的某个地方,在 Windows 的套接字层中。作为后续,当您说来自 .NET 的发送仅下行到内部 TCP/IP 缓冲区时,我不得不想知道 Wireshark 在哪里执行捕获。可能不在那个级别,但可能在网络接口实际发送数据时?如果是这种情况,那么我真的不知道我会做些什么来解决这个问题。
  • Wireshark 会低于 tcp/ip 缓冲...例如,它会在聚合后看到数据。您确定没有任何类型的防病毒软件到位吗?或者过滤您的 Wireshark 捕获的活动?
  • 当您说您看到来自客户端的数据包并且它们正在被确认时,这些数据包是否位于您无法发送的同一个套接字连接上?
  • 我确信这台机器上没有 AV,但它是我正在运行的虚拟机,如果这很重要的话。我的 Wireshark 上也没有激活过滤器...我实际上看到了我希望看到的所有内容,除了偶尔发生此错误时。我想我没有提到它,但这只会每 20-30 分钟发生一次。至于您的最后一个问题,来自客户端的收到 ACK 的数据包与失败的数据包位于同一连接上。
  • 我不太熟悉混合中的 VM 引起的其他问题。我知道您可以在 VM 实例上配置带宽限制?我想知道当这个问题发生时正在发生什么,您是否看到您发送的数据中出现了停电,或者,如果您仔细查看 Wireshark 日志,您是否看到现在应该发送的任何其他传出 ACK但那不见了?我很好奇所讨论的时间段是否导致您的连接完全出站中断,或者它只是您的数据框。
【解决方案3】:

如果可以忽略其限制,您是否可以重写应用程序以使用TcpClient 而不是Socket?如果您的应用程序无论如何都绑定到 TCP/IP,至少对于这个特定的套接字,您不妨使用抽象——它可能会有所帮助。另外,您可以尝试使用EndSend(IAsyncResult, SocketError) 重载来查看SocketError 对象是否包含任何有用的内容。

如果这些软件调整都没有帮助,我必须同意问题必须低于 .NET 软件级别,即防火墙软件(或硬件)、防病毒等。

【讨论】:

    【解决方案4】:

    这个问题是很久以前的问题了,所以你可能已经继续......如果其他人有同样的问题,你可能想检查 Windows 的 Memory Pressure Protection 是否可能会出现。这会导致数据包当有多个同时连接时被丢弃,这就是您所看到的。

    您可以尝试的另一个实验是暂时关闭服务器计算机上的防火墙。这也会关闭所有这些保护机制(如果我没记错的话),如果一切正常,你就知道其中一个就是罪魁祸首。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-06
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-16
      相关资源
      最近更新 更多