零字节接收:目的澄清

时间:2018-04-22 20:31:25

标签: network-programming winsock winsock2 iocp

我正在使用IO完成端口学习服务器开发。我的书“Microsoft Windows网络编程 - 第二版”说明如下:

  

对于每个重叠的发送或接收操作,很可能是   提交的数据缓冲区将被锁定。当内存被锁定时,它   无法从物理内存中分页。操作系统强制执行   限制可能被锁定的内存量。当这个限制是   到达时,重叠操作将因WSAENOBUFS错误而失败。如果   服务器在每个连接上发布许多重叠的接收,这个限制   将随着连接数量的增长而达到。如果是服务器   预计会处理大量的并发客户端   服务器可以在每个连接上发布单个零字节接收。因为   没有与接收操作相关的缓冲区,没有内存   需要锁定。使用这种方法,每个套接字接收缓冲区   应保持原样,因为一旦零字节接收操作   完成后,服务器可以简单地执行非阻塞接收   检索套接字接收缓冲区中缓冲的所有数据。那里   当非阻塞接收失败时,不再有数据待处理   WSAEWOULDBLOCK。

现在,我正试图理解这一段;我想我已经得到了它但是想确保

如果我发布带有大缓冲区的多个WSARecv()调用,我理解内存被锁定。但我不完全确定零字节缓冲区如何阻止这种情况。

我在想这是(并希望确认):

如果我有n个连接,并且我在每个连接上发布了带有1KB缓冲区的50个WSARecv()个调用,那么n * 50KB总内存已锁定。所有内存都被锁定,无论它是否实际被使用(即是否从TCP缓冲区中将任何内容复制到其中)。因此,如果我不断添加更多连接,我将继续锁定可能使用或可能使用的更多内存。因此,我可以用完WSAENOBUFS错误。

但是,如果我在每个连接上发布零字节接收,则仅当有可用于读取的数据时,才会在该连接上生成完成数据包。 (这是我的第一个假设,这是正确的吗?)

现在,当我知道有一些数据时,我可以发布一个带有1KB(或多少)缓冲区的WSARecv() - 或者确实按照我的书中的建议重复读取它 - 知道它将立即填写因此不会保持未使用状态并锁定 (第二个假设,这是正确的吗?)

问题1 因此,如果我的两个假设是正确的,那么我理解了我的书:)这意味着我的服务器理论上可以在建立新连接时发布零字节接收,然后当生成完成数据包时,读取所有直到没有更多的数据,然后发布另一个零字节接收 - 这是正确的吗?

问题2 但是,如果我收到批次我的零字节接收帖子一次,则仍然存在风险,然后我转到make 多个 WSARecv()来电,我仍然会因WSAENOBUFS而失败?

希望有人可以为我澄清这两个假设和两个问题。

1 个答案:

答案 0 :(得分:0)

好的我已经对此进行了研究并进行了实验,并找到了以下内容:

<强>假设:

1)假设1是正确的。 2)我认为假设2是正确的。

<强>问题

1)我测试了这个,这似乎有效。 2)我猜这仍然是一种可能性,但比我用非零缓冲区发布接收的可能性要小得多。

请注意,我们仍然可以在发送速度过快时引发WSAENOBUF错误;更多详情here