【问题标题】:C# Socket is every one Receive corresponds to one Send?C# Socket是每一个Receive对应一个Send吗?
【发布时间】:2020-12-10 16:11:33
【问题描述】:

我正在使用 C# Socket 类(使用异步方法和 SocketAsyncEventArgs 类)实现客户端-服务器应用程序。我必须同时实现 TCP 和 UDP 功能。

我的用法是以数据包的形式从服务器向客户端发送一些命令,反之亦然,对重要命令使用 TCP,对非重要命令使用 UDP。

据说 Nagle 算法可能会导致 TCP 数据包的多个发送合并到一个接收,所以我为 TCP 套接字设置了NoDelay(虽然我从未经历过!)

另一个问题可能是 IP 碎片,但我认为组装碎片发生在接收之前的某个地方。因此,一次发送和接收最多 64KB 的数据必须是安全的!

我的问题::我能否假设在 100% 的情况下,每个 一个 Receive 对应于 一个 Send? (我知道一次发送可能导致 UDP 丢失数据包的零接收)

我问的原因:我应该实施 1)拆分合并数据包还是 2)合并拆分接收中的数据包,还是有一些 情况?

P.S:我将Socket.ReceiveAsync 用于 TCP,Socket.ReceiveFromAsync 用于 UDP 数据包。

【问题讨论】:

  • 我发现这个答案很有用:Link
  • 另见this

标签: c# sockets tcp udp


【解决方案1】:

不,对于 TCP,您根本不能依赖它。一个Send 可能需要多次调用Receive 才能读取,一次调用Receive 可能会收到多个Sends,您无能为力(就连接设置而言)来防止这种情况发生,因此您必须能够在您的应用程序中处理它。

如果您通过 TCP 流交换可变长度的消息,确定是否已读取整个消息的常用方法是实现某种形式的“帧”,即在每条消息前面加上固定数量的字节(例如 4用于编码Int32) 的字节,指定以下消息的大小。

在接收端,您首先读取前 4 字节前缀(请记住,您可能需要对多个 Receives 执行此操作!),将其转换为 Int32,然后告诉您您还有多少字节'将需要阅读以确保您已从流中准确地阅读了一条消息。要阅读下一条消息,只需重复该过程即可。

【讨论】:

  • 谢谢!您能否具体说明可能发生这种情况的地点和原因?您的建议正是我打算实施的,但根据我的经验,这似乎是多余的,因为我没有经历过合并/拆分。
  • 你的意思是在某些方面某些路由器或 ISP 可能会合并或拆分数据包?对于 TCP 和 UDP?
  • @Mokhabadi - 它可能发生在数据路径上的任何点,并且有多种原因 - 例如(但不是它可能发生的唯一原因),您 Send() 的数据被拆分成数据包(大小有限)通过网络发送出去。如果您的链接速度较慢,并在所有数据包到达之前在目的地调用Receive(),您的操作系统可能会为您提供迄今为止收到的所有数据,但这将少于传递给Send() 的数据量来源。另一方面,UDP 是一种数据报协议,因此旨在发送消息,而不是像 TCP 那样的数据流
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 2014-11-19
  • 2021-06-24
  • 2012-07-25
  • 1970-01-01
相关资源
最近更新 更多