我的问题:我的Completionport服务器将从不同的客户端接收未知大小的数据,事实是,我不知道如何避免缓冲区溢出/如何避免我的(接收)缓冲区被数据“过满”。 / p>
现在问问题: 1)如果我通过WSARecv进行接收呼叫,那么workerthread是否像回调函数一样工作?我的意思是,只有在接收电话完成时才开始接收电话,还是在接收发生时也将其挖出来? lpNumberOfBytes(来自GetQueuedCompletionStatus)变量是否包含到目前为止接收的字节数或接收的总字节数?
2)如何避免超支,我想到了动态分配的缓冲区结构,但话又说回来,我怎么知道这个包有多大?
编辑:我讨厌问这个,但有没有“简单”的方法来管理缓冲区并避免超支?同步对我来说听起来不受限制,至少现在
答案 0 :(得分:1)
_1。完成端口是一种队列(具有复杂的逻辑,涉及等待从中取出I / O完成的线程的优先级)。每当I / O完成(成功或不成功)时,它就会排队到完成端口。然后它被称为GetQueuedCompletionStatus
的一个线程出列。
因此,您永远不会将I / O"正在进行中"。而且,它是由您的工作线程异步处理的。也就是说,它延迟到你的线程调用GetQueuedCompletionStatus
。
_2。这实际上是一件复杂的事情。同步并不是一项简单的任务,特别是在涉及对称多线程时(你有多个线程,每个线程都可以做任何事情)。
使用完整的I / O接收的参数之一是指向OVERLAPPED
结构的指针(您提供给发出I / O的函数,例如WSARecv
)。分配基于OVERLAPPED
的自己的结构(通过继承它或将其作为第一个成员)是一种常见做法。收到完成后,您可以将出列的OVERLAPPED
投射到您的实际数据结构中。在那里,您可能拥有同步所需的一切:同步对象,状态描述等。
但请注意,即使您拥有自定义上下文,也无法正确同步事物(以获得良好的性能并避免死锁)。这需要精确的设计。
答案 1 :(得分:1)
如果我通过WSARecv拨打电话,那么workerthread是否像回调函数一样工作?
请参阅@valdo帖子。完成数据排队到您的线程池,其中一个将准备好处理它。
'我的意思是,只有在完成接收电话时才开始接收电话吗?'是的 - 因此得名。请注意,“已完成”的含义可能会有所不同。取决于协议。使用TCP,这意味着已从对等方接收到一些流数据字节。
'lpNumberOfBytes(来自GetQueuedCompletionStatus)变量是否包含到目前为止接收的字节数或接收的总字节数?'它包含仅在IOCP完成时提供的缓冲区数组中接收和加载的字节数。
'如何避免超支,我想到了动态分配的缓冲区结构,但话又说回来,我怎么知道这个包有多大?如果提供缓冲区数组,则无法获得溢出 - 加载缓冲区的内核线程将不会超过传递的缓冲区长度。在应用程序级别,鉴于TCP的流式特性,由您决定如何将缓冲区阵列处理为可用的应用程序级协议单元。您必须根据所提供服务的知识,通过适当的缓冲管理方案来决定。
最后一个IOCP服务器是通用的。我使用了一个缓冲池数组和一个“缓冲区载体”对象池,它们在启动时分配(以及一个套接字对象池)。每个缓冲池都保存不同大小的缓冲区。在新连接时,我使用最小池中的一个缓冲区发出了WSARecv。如果这个缓冲区被完全填满,我使用下一个最大池中的缓冲区作为下一个WSARecv,依此类推。
然后出现了防止多个处理程序线程无序缓冲所需的序列号问题:(