我正在使用IO完成端口学习服务器开发。我的书“Microsoft Windows网络编程 - 第二版”说明如下:
对于每个重叠的发送或接收操作,很可能是 提交的数据缓冲区将被锁定。当内存被锁定时,它 无法从物理内存中分页。操作系统强制执行 限制可能被锁定的内存量。当这个限制是 到达时,重叠操作将因WSAENOBUFS错误而失败。如果 服务器在每个连接上发布许多重叠的接收,这个限制 将随着连接数量的增长而达到。如果是服务器 预计会处理大量的并发客户端 服务器可以在每个连接上发布单个零字节接收。因为 没有与接收操作相关的缓冲区,没有内存 需要锁定。使用这种方法,每个套接字接收缓冲区 应保持原样,因为一旦零字节接收操作 完成后,服务器可以简单地执行非阻塞接收 检索套接字接收缓冲区中缓冲的所有数据。那里 当非阻塞接收失败时,不再有数据待处理 WSAEWOULDBLOCK。
现在,我正试图理解这一段;我想我已经得到了它但是想确保。
如果我发布带有大缓冲区的多个WSARecv()
调用,我理解内存被锁定。但我不完全确定零字节缓冲区如何阻止这种情况。
我在想这是(并希望确认):
如果我有n
个连接,并且我在每个连接上发布了带有1KB缓冲区的50个WSARecv()
个调用,那么n * 50KB
总内存已锁定。所有内存都被锁定,无论它是否实际被使用(即是否从TCP缓冲区中将任何内容复制到其中)。因此,如果我不断添加更多连接,我将继续锁定可能使用或可能使用的更多内存。因此,我可以用完WSAENOBUFS
错误。
但是,如果我在每个连接上发布零字节接收,则仅当有可用于读取的数据时,才会在该连接上生成完成数据包。 (这是我的第一个假设,这是正确的吗?)
现在,当我知道有一些数据时,我可以发布一个带有1KB(或多少)缓冲区的WSARecv()
- 或者确实按照我的书中的建议重复读取它 - 知道它将立即填写因此不会保持未使用状态并锁定 (第二个假设,这是正确的吗?)
问题1 因此,如果我的两个假设是正确的,那么我理解了我的书:)这意味着我的服务器理论上可以在建立新连接时发布零字节接收,然后当生成完成数据包时,读取所有直到没有更多的数据,然后发布另一个零字节接收 - 这是正确的吗?
问题2
但是,如果我收到批次我的零字节接收帖子一次,则仍然存在风险,然后我转到make 多个 WSARecv()
来电,我仍然会因WSAENOBUFS
而失败?
希望有人可以为我澄清这两个假设和两个问题。
答案 0 :(得分:0)
好的我已经对此进行了研究并进行了实验,并找到了以下内容:
<强>假设:强>
1)假设1是正确的。 2)我认为假设2是正确的。
<强>问题强>
1)我测试了这个,这似乎有效。 2)我猜这仍然是一种可能性,但比我用非零缓冲区发布接收的可能性要小得多。
请注意,我们仍然可以在发送速度过快时引发WSAENOBUF
错误;更多详情here。