【发布时间】:2018-04-22 20:31:25
【问题描述】:
我正在学习使用 IO 完成端口进行服务器开发。我的书“Microsoft Windows 网络编程 - 第二版”陈述如下:
对于每个重叠的发送或接收操作,很可能 提交的数据缓冲区将被锁定。当内存被锁定时,它 不能从物理内存中调出。操作系统强加了一个 限制可能被锁定的内存量。当这个限制是 达到时,重叠操作将失败并出现 WSAENOBUFS 错误。如果 服务器在每个连接上发布许多重叠接收,此限制 将随着连接数的增长而达到。如果一个服务器 预计处理大量并发客户端, 服务器可以在每个连接上发布单个零字节接收。因为 没有与接收操作相关的缓冲区,没有内存 需要锁定。使用这种方法,每个套接字的接收缓冲区 应该保持原样,因为一旦零字节接收操作 完成后,服务器可以简单地执行一个非阻塞接收到 检索套接字接收缓冲区中缓冲的所有数据。那里 当非阻塞接收失败时,不再有待处理的数据 WSAEWOULDBLOCK。
现在,我正在尝试理解这一段;我想我知道了但想确认一下。
我了解如果我发布多个带有大缓冲区的 WSARecv() 调用,内存会被锁定。但我不完全确定零字节缓冲区如何防止这种情况。
我想是这样的(请确认):
如果我有 n 连接,并且我发布了 50 个 WSARecv() 调用,每个连接上的缓冲区为 1KB,则 n * 50KB 总内存被锁定。所有内存都被锁定,无论它是否实际被使用(即是否有任何东西从 TCP 缓冲区复制到其中)。因此,如果我继续添加更多连接,我将继续锁定更多可能会或可能会使用的内存。这样我就可以用完了,WSAENOBUFS 错误。
如果我在每个连接上发布一个零字节接收,则该连接上将生成一个完成数据包只有当有数据可供读取时。 (这是我的第一个假设,对吗?)
现在,当我知道有一些数据时,我可以发布一个 WSARecv(),其缓冲区为 1KB(或更多) - 或者确实按照我书中的建议循环重复阅读所有内容 - 知道它会是立即填充因此不会保持未使用和锁定 (第二个假设,对吗?)
问题 1 因此,如果我的两个假设是正确的,那么我已经理解了我的书 :) 这意味着理论上我的服务器可以在建立新连接时发布零字节接收,然后在生成完成数据包时读取所有直到没有更多数据,然后发布另一个零字节接收 - 正确吗?
问题 2
但是,如果我收到 lots 我的零字节接收帖子一次的完成数据包,是否仍然存在风险,然后我继续制作 multiple WSARecv() 调用,我仍然会以 WSAENOBUFS 失败而告终?
希望有人可以为我澄清这两个假设和两个问题。
【问题讨论】:
-
我发布了 50 个 WSARecv() 调用 - 首先在同一端点发布多个 recv 是逻辑错误。每次必须只有一个 recv。其次,我认为使用 0 revc 缓冲区是个坏主意。仅在 ~2 时间内增加接收计数
-
好的,我在多个地方读到过,发布多个
WSARecv电话实际上是个好主意。你能评论我从书中引用的内容吗?不是它是否是一个好主意,而是我是否理解它?谢谢。 -
不,多次 WSARecv 调用是致命的逻辑错误。如果 2 个 recv 同时完成 - 你如何确定哪个是第一个,哪个是第二个?
-
2 recv io 几乎同时完成。 2 个数据包排队到 iocp。 2 个不同的工作线程删除了这个数据包。这一切都是可以的。问题 - 此时您如何确定 - 首先是哪个数据包,哪个是第二个?没有意义在 tcp 套接字上有多个 recv
-
您将某种“排序”添加到接收呼叫中,然后按设置的顺序处理它们。 codeproject.com/Articles/2610/…。如果你不同意也没关系,但我只是想澄清一下,我已经正确理解了我的书。
标签: network-programming winsock winsock2 iocp