【问题标题】:C# Socket.Send( ): does it send all data or not?C# Socket.Send():它是否发送所有数据?
【发布时间】:2018-09-12 07:21:39
【问题描述】:

我正在从 Richard Blum 的一本名为“C# Network Programming”的书中阅读有关套接字的内容。以下摘录指出 Send() 方法不能保证发送传递给它的所有数据。

byte[] data = new byte[1024];
int sent = socket.Send(data);

根据这段代码,您可能会认为 整个 1024 字节的数据缓冲区被发送到远程设备……但这 可能是一个糟糕的假设。取决于内部 TCP 的大小 缓冲区以及正在传输的数据量,有可能不是 提供给 Send() 方法的所有数据实际上都已发送。

但是,当我查看 Microsoft 文档 https://msdn.microsoft.com/en-us/library/w93yy28a(v=vs.110).aspx 时,它说:

如果您使用的是面向连接的协议,Send 将阻塞,直到 缓冲区中的所有字节都被发送,除非设置了超时

那是什么?这本书是 2004 年出版的,那么从那以后它有什么变化吗?

我打算使用异步套接字,所以我的下一个问题是,BeginSend() 会发送所有数据吗?

【问题讨论】:

  • 你没在文档里看到吗 - "Returns: The number of bytes sent to the Socket"
  • @Micky:忽略文档以支持黑盒观察是一个非常糟糕的主意,这会导致代码在其他计算机上失败,在 Windows 更新之后,甚至当您的计算机碰巧有更多或准备好同时运行的线程更少。
  • @BenVoigt 也许吧。但是话又说回来,文档形成了合同,如果行为取决于环境,那么文档应该这样说
  • @MickyD:确实,文档形成了合同。所有环境都必须遵守该合同。某些环境可能做得更多,但文档不需要详细说明合同之外的任何内容。
  • @BenVoigt 好的,谢谢哥们

标签: c# .net sockets tcp


【解决方案1】:

您所要做的就是阅读与您引用的完全相同的段落的其余部分。你在同一句话中的引用甚至有一个例外。

如果您使用面向连接的协议,Send 将阻塞,直到缓冲区中的所有字节都发送完毕,除非使用 Socket.SendTimeout 设置了超时。如果超过超时值,Send 调用将抛出 SocketException。 在非阻塞模式下,即使发送的字节数少于缓冲区中的字节数,发送也可能成功完成。您的应用程序有责任跟踪发送的字节数并重试操作,直到应用程序发送缓冲区中的字节。

对于BeginSend,也描述了行为:

您的回调方法应该调用 EndSend 方法。当您的应用程序调用 BeginSend 时,系统将使用单独的线程来执行指定的回调方法,并且将阻塞 EndSend,直到 Socket 发送请求的字节数或抛出异常。

这不是一个很好的设计,并且破坏了回调的全部意义!考虑改用SendAsync(然后您仍然需要检查BytesTransferred 属性)。

【讨论】:

    【解决方案2】:

    您引用的两个资源都是正确的。我认为措辞本来可以更好。 在文档中,MSDN 也这样写

    也不保证您发送的数据会出现在 立即联网。为了提高网络效率,底层 系统可能会延迟传输,直到有大量的传出 收集数据。

    所以Send 方法会阻塞,直到底层系统有空间缓冲您的数据以进行网络发送。

    成功完成 Send 方法意味着底层 系统有空间来缓冲您的数据以进行网络发送。

    【讨论】:

      猜你喜欢
      • 2015-01-18
      • 1970-01-01
      • 2015-08-18
      • 2012-11-08
      • 2017-07-22
      • 2018-08-27
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多