我正在学习使用IO完成端口的服务器开发。我的书“Microsoft的网络编程-第二版”说明如下:
对于每个重叠的发送或接收操作,提交的数据缓冲区很可能会被锁定。当内存被锁定时,它不能从物理内存中分页。操作系统对可能被锁定的内存量施加了限制。当达到此限制时,重叠操作将因WSAENOBUFS错误而失败。如果服务器在每个连接上发送许多重叠的接收信息,则随着连接数量的增加,将达到此限制。如果服务器期望处理大量并发客户端,则服务器可以在每个连接上发送单个零字节接收。因为没有与接收操作相关联的缓冲区,所以不需要锁定内存。使用这种方法,每个套接字接收缓冲区应该保持原样,因为一旦零字节接收操作完成,服务器就可以执行非阻塞接收来检索套接字接收缓冲区中的所有数据缓冲区。当WSAEWOULDBLOCK非阻塞接收失败时,不再有数据挂起。
现在,我正在努力理解这段话,我想我已经理解了,但我想确定一下。
我了解如果我在post中使用大型缓冲区进行多个WSARecv()调用,内存就会被锁定。但我不完全确定零字节缓冲区是如何防止这种情况的。
我想是这样(请确认一下):
如果我有n连接,并且在每个连接上发布了50个带有1KB缓冲区的WSARecv()调用,即n * 50KB总内存锁定。所有这些内存都被锁定,不管是否实际使用它(即是否从TCP缓冲区将任何内容复制到内存中)。因此,如果我继续添加更多的连接,我将继续锁定更多的内存,这些内存可能或可能会被使用。因此,如果出现WSAENOBUFS错误,我就可以用完。
但是,如果我在每个连接上发布一个零字节接收,则只有当有可读取的数据时,才会在该连接上生成一个完成包。(这是我的第一个假设,对吗?)
现在,当我知道有一些数据时,我就可以发布一个缓冲区为1KB (或多少)的WSARecv() --或者按照我的书中的建议反复阅读它--知道它会立即被填充,因此不会被使用和锁定(第二个假设,是正确的吗?)
因此,问题1,如果我的两个假设是正确的,那么我就理解了我的书:)这意味着,理论上,我的服务器可以在建立新连接时发送一个零字节接收,然后当生成一个完成包时,读取所有数据直到没有更多的数据,然后再发送一个零字节接收--这是正确的吗?
然而,问题2,如果我立即收到lots的完成包(0字节的接收),然后再进行多个 WSARecv()调用,那么我是否仍然会遇到一些WSAENOBUFS失败的风险?
希望有人能为我澄清这两个假设和两个问题。
发布于 2018-04-27 09:54:45
好的,我对此进行了研究,并进行了实验,并发现如下:
假设:
1)假设1是正确的。2)我相信假设2是正确的。
问题
1)我对此进行了测试,这似乎是可行的。( 2)我想这仍然是一种可能性,但比我用无零缓冲区投递收件的可能性小得多。
注意,我们仍然可以在发送太快时引发WSAENOBUF错误;更详细的这里。
https://stackoverflow.com/questions/49970454
复制相似问题