Windows 从异步套接字最佳地读取数据

Windows 从异步套接字最佳地读取数据,windows,sockets,Windows,Sockets,我对使用WSAASyncSelect将套接字置于异步模式的套接字库有一个问题。在异步模式下,套接字被置于非阻塞模式(任何将阻塞的操作都会返回WSAWOULDBLOCK),windows消息被发布到通知窗口,以通知应用程序套接字何时可以读取、写入等 我的问题是,当接收FD_读取事件时,我不知道要尝试和接收多少字节。如果我传递的缓冲区太小,winsock将自动发布另一个FD_读取事件,告诉我还有更多数据要读取。如果数据到达速度非常快,这可能会使消息队列中充满FD_读取消息,而WM_TIMER和WM_

我对使用WSAASyncSelect将套接字置于异步模式的套接字库有一个问题。在异步模式下,套接字被置于非阻塞模式(任何将阻塞的操作都会返回WSAWOULDBLOCK),windows消息被发布到通知窗口,以通知应用程序套接字何时可以读取、写入等

我的问题是,当接收FD_读取事件时,我不知道要尝试和接收多少字节。如果我传递的缓冲区太小,winsock将自动发布另一个FD_读取事件,告诉我还有更多数据要读取。如果数据到达速度非常快,这可能会使消息队列中充满FD_读取消息,而WM_TIMER和WM_PAINT消息仅在消息队列为空时发布,这意味着如果应用程序接收大量数据并使用缓冲区过小的异步套接字,则可能会停止绘制

那么缓冲区有多大?我尝试使用ioctlsocket(FIONREAD)来获取要读取的字节数,并使缓冲区正好如此大,但是,明确警告说这种方法效率低下


如何选择足够大但又不疯狂大的缓冲区大小?

如果发送方发送了较小的消息,您可以在不影响性能的情况下将缓冲区设置为尽可能大,依靠TCP PUSH标志使读取返回,然后再填充缓冲区

TCP推送标志设置在逻辑消息边界(通常在发送操作之后,除非显式设置为false)。当接收端看到TCP数据包上的PUSH标志时,它将返回任何阻塞读取(或异步读取,无所谓),并将接收缓冲区中累积的内容返回到PUSH点


因此,如果您的发件人发送的邮件大小合理,您可以,如果他不可以,那么您可以限制缓冲区大小,这样即使您通读了所有内容,也不会对性能产生负面影响(主观)。

据我所知,使用
setsockopt
sorvcbuf
选项设置的值是
FIONREAD
值的上限。因此,与其调用
ioctlsocket
,不如调用
getsockopt
找出
So\u RCVBUF
设置,并将其用作每个
recv
的(尝试)值

根据你对Aviad p.回答的评论,听起来这会解决你的问题


(免责声明:我自己一直使用
FIONREAD
。但在阅读链接到KB的文章后,我可能会改变…

我并不担心大量阅读会很快返回。在我的上下文中,我执行recv以响应FD_读取事件,因此它保证recv将立即返回某些内容,而不会尝试阻止。我的问题是,如何计算recv缓冲区的大小,以便在一次recv调用中排出所有挂起的数据。我可以把它设为1Mb,但摩尔定律暗示,即使在不远的某一天,它也可能太小,而今天仍然是对资源的疯狂浪费。只是好奇,你为什么要计算它?你不能一次循环一个数据块吗?我会选择SO_RCVBUF作为最合理的缓冲区大小。