单缓冲区阻塞WSASend可以提供部分数据吗?

时间:2014-04-02 19:30:46

标签: c++ winapi winsock winsock2

我几乎总是将send()用于套接字,现在我转移到WSA函数。使用send(),我有一个sendall()帮助程序,即使在一次尝试中没有发生并且在第一次调用时发生部分发送,也可以确保所有数据都已传送。

因此,在我不必要的时候,不是学习困难的方法或过度复杂的代码,而是决定问你:

  

阻止WSASend()可以发送部分数据还是在返回或失败之前发送所有内容?或者我应该检查发送的字节数与预期发送的字节数并保持不变交付?

ANSWER 重叠WSASend()不会发送部分数据,但如果发生,则表示连接已终止。我还没有遇到过这个案子。

1 个答案:

答案 0 :(得分:4)

来自WSASend文档:

  

如果套接字是非阻塞且面向流的,并且传输缓冲区中没有足够的空间,WSASend将返回,只有部分应用程序的缓冲区已被占用。给定相同的缓冲区情况和阻塞套接字,WSASend将阻塞,直到所有应用程序缓冲区内容都被使用。

我没有尝试过这种行为。顺便说一句,为什么要重写代码才能使用WSA功能?从标准的bsd套接字api切换到基本上使用相同的阻塞行为的套接字对我来说似乎并不是一个好主意。只需将带有send的旧阻止代码与“重试代码”保持一致,这样便携式和防弹。它不能保存1-2比较,这使得你的IO代码具有高性能。

仅当您尝试利用某些特定于Windows的强度时,或者如果您想要使用WSAWaitForMultipleObjects比标准select好一点的非阻塞套接字,请切换到专门的WSA函数但即使在这种情况下,您也可以像我一样使用sendrecv

在我看来,使用epoll / kqueue / iocp(或抽象这些文件的库)是套接字的方法。有一些非常基本的任务可以通过阻塞套接字完成,但是如果你越过线并且你需要非阻塞袜子,那么直接切换到epoll / kqueue / iocp是一种方法,而不是编写痛苦的select或{{ 1}}基于apis。 epoll / kqueue / iocp不仅比基于WSAWaitForMultipleObjects的替代方案更好,而且更容易编程。真。它们是更现代的apis,是基于更多经验而发明的。 (虽然它们不是跨平台,但即使选择也有可移植性问题......)。

前面提到的linux / bsd / windows的apis基于相同的概念,但在我看来,最简单和最容易学习的是linux的epoll api。它比select调用更好,但是一旦你明白了,它就会更容易编程。如果你开始在Windows上使用IOCP而不是我看起来有点复杂。

如果您尚未使用这些api,那么如果您熟悉linux,那么肯定会给epoll一个机会,然后在Windows上实现相同的IOCP基于类似的概念和更复杂的重叠IO编程。使用IOCP,您将有理由使用select,因为您无法在WSASend的套接字上启动重叠IO,但您可以使用send(或WSASend)执行此操作。

编辑:如果您希望获得IOCP的最高性能,那么这里有一些额外的提示:

  • 删除阻止操作。这是非常重要的。一个严肃的网络引擎无法承受阻塞IO。它根本无法在任何平台上扩展。发送和接收都是重叠的操作,重叠的IO是Windows的大枪。
  • 设置处理已完成的IO操作的线程池。设置测试客户端,使用类似于实际用途的消息和并行连接计数轰炸您的服务器,并在压力下调整实际目标硬件的缓冲区大小和线程数。
  • 将套接字的SO_RCVBUF和SO_SNDBUF大小设置为零,并使用您用于发送和接收数据的缓冲区大小。将套接字句柄的rcv / send buf设置为零允许tcp堆栈直接向/从缓冲区接收/发送数据,从而避免在用户空间缓冲区和套接字缓冲区之间进行额外复制。这些缓冲区的最佳大小也需要调整。我通常使用至少几十K个缓冲区大小,但有时在大容量传输的情况下,1-2M缓冲区大小更好,具体取决于并行繁忙连接的数量。再次,调整值,同时强调服务器的一些测试客户端执行类似于真实客户端的活动。当您准备好使用网络引擎的第一个工作版本时,可以构建一个可以模拟许多(可能是数千个)并行客户端的测试客户端,具体取决于您服务器的实际使用情况。
  • 您的网络引擎中需要“每个连接软件发送缓冲区”,您可能(或可能不想)控制发送缓冲区的最大大小。如果达到最大发送缓冲区大小,您可能希望阻止或丢弃消息/数据,具体取决于您要执行的操作,封装此特殊缓冲区并为其提供两个不错的接口:一个用于将数据放入此缓冲区的线程以及IOCP发送方代码使用的另一个接口。这个缓冲区通常是整个事情的一个非常关键的部分,我通常在代码的这一部分有很多错误,所以一定要很好地设计它的接口,以尽量减少错误的数量。根据应用程序构造和将消息放入队列的方式,您可以使用内部实现(存储块的大小,类似于类似的优化,......)来进行大量操作。