c++ - 单缓冲区阻塞WSASend可以传递部分数据吗?

标签 c++ winapi winsock winsock2

我几乎总是将send()与套接字一起使用,现在我转向WSA函数。使用send(),我有一个sendall()帮助器,即使一次尝试都没有发生任何数据,并且在第一次调用时发生部分发送,它也可以确保所有数据都已传递。

因此,我决定不问您,而不是刻苦学习或在不需要时过度编写代码,而是决定:

Can a blocking WSASend() send partial data or does it send everything before it returns or fails? Or should I check the bytes sent vs. expected to send and keep at it until everything is delivered?



ANSWER :重叠的WSASend()不发送部分数据,但如果发送,则表示连接已终止。我还没有遇到过这种情况。

最佳答案

WSASend文档:

If the socket is non-blocking and stream-oriented, and there is not sufficient space in the transport's buffer, WSASend will return with only part of the application's buffers having been consumed. Given the same buffer situation and a blocking socket, WSASend will block until all of the application buffer contents have been consumed.



我还没有尝试过这种行为。顺便说一句,为什么您要重写代码以使用WSA功能?从标准bsd套接字api切换到基本上使用具有相同阻塞行为的套接字对我来说似乎并不是一个好主意。只需将旧的阻止代码与send一起保留在“重试代码”中,这样​​便可以移植且防弹。不保存1-2个比较就是使您的IO代码具有高性能。

仅当您尝试利用Windows的某些特定优势时,或者您要使用WSAWaitForMultipleObjects比标准select更好一些的非阻塞套接字时,才切换到WSA专业功能,即使在这种情况下,您也可以简单地使用sendrecv一样。

在我看来,使用带有套接字的epoll / kqueue / iocp(或将它们抽象化的库)是可行的方法。使用阻塞套接字可以完成一些非常基本的任务,但是如果您越界并且需要无阻塞的 socks ,那么直接切换到epoll / kqueue / iocp是一种方法,而不是编写痛苦的基于select或基于WSAWaitForMultipleObjects的api。与基于select的替代方案相比,epoll / kqueue / iocp不仅更好,而且更易于编程。真。它们是根据更多经验发明的更现代的api。 (尽管它们不是跨平台的,但即使选择也存在可移植性问题...)。

前面提到的用于linux / bsd / windows的api基于相同的概念,但在我看来,最简单易学的是linux的epoll api。它比select调用要好得多,但是一旦您想到,它的编程就会容易100倍。如果您开始在Windows上使用IOCP,那我看起来会更复杂一些。

如果您还没有使用过这些api,那么如果您熟悉linux,那么一定可以使用epoll,然后在Windows上使用基于类似概念的IOCP来实现相同的功能,并使用一些复杂的重叠IO编程。使用IOCP,您将有理由使用WSASend,因为您无法使用send在套接字上开始重叠的IO,但可以使用WSASend(或WriteFile)来实现。

编辑:如果要使用IOCP以获得最高性能,那么这里有一些其他提示:
  • 删除阻止操作。这个非常重要。严重的网络引擎负担不起阻塞IO。它根本无法在任何平台上扩展。对发送和接收都执行重叠操作,重叠IO是Windows的大手枪。
  • 设置用于处理已完成的IO操作的线程池。设置测试客户端,使用真实世界中的使用情况消息和并行连接数轰炸您的服务器,并在压力下调整实际目标硬件的缓冲区大小和线程数。
  • 将套接字的SO_RCVBUF和SO_SNDBUF大小设置为零,并使用要用于发送和接收数据的缓冲区的大小。将套接字句柄的rcv / send buf设置为零将使tcp堆栈直接从缓冲区接收数据/从缓冲区发送数据,从而避免在用户空间缓冲区和套接字缓冲区之间进行额外的复制。这些缓冲区的最佳大小也会受到调整。我通常至少使用几十个K缓冲区大小,但有时在大容量传输的情况下,根据并行繁忙连接的数量,最好使用1-2M缓冲区大小。再次,调整值,同时用一些测试客户端对服务器施加压力,这些客户端的 Activity 类似于真实世界的客户端。当您准备好在其之上的第一个工作版本的网络引擎时,就可以构建一个测试客户端,该客户端可以根据服务器的实际使用情况模拟许多(也许数千个)并行客户端。
  • 您将需要网络引擎内部的“每个连接软件发送缓冲区”,并且您可能(或可能不需要)控制发送缓冲区的最大大小。在达到最大发送缓冲区大小的情况下,您可能要根据要执行的操作来阻止或丢弃消息/数据,封装此特殊缓冲区并为其提供两个漂亮的接口(interface):一个用于将数据放入此缓冲区的线程以及IOCP发送者代码使用的另一个接口(interface)。这个缓冲区通常是整个过程中非常关键的部分,而且我在这部分代码中通常会有很多错误,因此请确保将其接口(interface)设计得很好,以最大程度地减少错误的数量。根据您的应用程序构造和将消息放入队列的方式,您可以使用内部实现(存储块的大小,类似nagle的优化等)进行很多操作。
  • 关于c++ - 单缓冲区阻塞WSASend可以传递部分数据吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22821214/

    相关文章:

    c++ - STXXL 的高内存使用率

    c++ - 限制在 C++ 中的堆和堆栈上创建对象

    c++ - TreeListView 控件

    c++ - 编辑控件捕获回车键

    c++ - 为什么我在使用 winsock 时收不到 UDP 数据包?

    c++ - 使用 Winsock 的简单 HTTP 获取

    c++ - WSAGetLastError() 返回 122

    c++ - 如果派生类具有私有(private)变量,则派生类数组不起作用

    c++ - 相机同步

    python - Pycharm win32api模块安装错误: Non-zero exit code (1)