.Net 异步套接字操作限制?
Posted
技术标签:
【中文标题】.Net 异步套接字操作限制?【英文标题】:.Net asynchronous socket operations limit? 【发布时间】:2011-02-28 15:09:05 【问题描述】:待处理的异步操作是否是应谨慎使用的宝贵资源?
我有大量已连接的 TcpClients,但我不希望它们从中输入,但以防万一出现行为不端,我需要将输入缓冲区保持为空。如果我为每个连接的客户端都有一个 BeginRead() 并且无限期地保持打开状态,有什么危害吗?当客户端最终关闭时,回调将被调用,如果 !asyncResult.IsCompleted 我可以退出它。
虽然我相信我可以共享一个缓冲区,但我不知道要开始读取多少字节。达到该缓冲区限制的输入可能只是位于流中,未读。有没有更好的方法来有效地丢弃、禁止或等待流中数据的可用性?
否则我需要轮询可用的数据。
谢谢!
【问题讨论】:
【参考方案1】:这取决于您运行的操作系统...
挂起的recv 将使用一些非分页池,它会导致一些内存页面被锁定以进行I/O。
在 Windows Vista 之前,非分页池非常可怕,它是一种机器范围内的商品,如果用完可能会导致设计不佳的驱动程序崩溃......所以在 Vista 之前的操作系统上,您可能会收到“ENOBUFS”错误由于缺少非分页池,来自底层的重叠 I/O 系统。有关非分页池限制的更多详细信息,请参见此处:http://www.lenholgate.com/blog/2009/03/excellent-article-on-non-paged-pool.html。
待处理的recv 使用的另一个资源是一个或多个内存页在操作挂起时被锁定用于i/o。可以锁定的页面数量是有限的,因此在某些情况下,您可能会再次从底层 I/O 系统获得“ENOBUFS”。
当然,这取决于你有多少连接,这些限制是否会影响你。
处理非托管代码中锁定的 I/O 页面限制的“标准”方法是发布零字节读取,即具有实际上 0 字节长的缓冲区的读取。这意味着在读取挂起时没有锁定缓冲区空间,当它完成时,您只需发布正常读取或同步读取。
【讨论】:
Reflector 显示 0 字节读取技巧应该在同步和异步模式下的Socket
和 NetworkStream
上的托管代码中工作。但是,您仍然需要传递一个缓冲区,它将由 .NET 固定。它是否会被操作系统锁定是另一回事。至于非分页池消耗,同步recv是否使用(几乎)相同数量的非分页池?毕竟只有用户代码将其视为“同步”,并且 IRP 处理在两种情况下都是相同的。
您在零字节读取返回后使用同步读取。你知道有数据,所以不需要异步。据我所知,它使用相同的非分页池【参考方案2】:
不,他们不是。除了你最终使用的套接字之外,异步操作还使用一个事件——最轻量级的内核对象——和一个OVERLAPPED
结构,即几个内存字。我希望您在事件或内存用完之前很久就会用完套接字。
似乎没有机制可以等待数据而不读取它在 .NET 中(底层 Win32 API 允许这样做,请参阅WSAEventSelect
),因此您必须阅读 1字节。建议在多个套接字之间共享一个大缓冲区,读取不同的偏移量,因为用于异步 i/o 的任何缓冲区都必须保持固定,直到 i/o 完成。
【讨论】:
谢谢!我在您发表评论时进行了编辑。我不知道要异步读取多少字节。我可以从一个开始,然后开始询问有多少可用,如果没有,请返回 1。这样做是否可取?以上是关于.Net 异步套接字操作限制?的主要内容,如果未能解决你的问题,请参考以下文章