我的循环错了吗?我是不是滥用 ReadFile() 和 I/O 完成端口?

Posted

技术标签:

【中文标题】我的循环错了吗?我是不是滥用 ReadFile() 和 I/O 完成端口?【英文标题】:Is my loop wrong ? Do I misuse ReadFile() and I/O completion port ?我的循环错了吗?我是否滥用 ReadFile() 和 I/O 完成端口? 【发布时间】:2011-04-08 07:22:50 【问题描述】:

我想使用命名管道(用于 IPC)实现服务器/客户端。我正在使用异步(重叠)连接和 I/O 完成端口(我搜索了很多,似乎这是最有效的方法这样做)。

首先是代码:

服务器:http://pastebin.com/XxeXdunC

和客户:http://pastebin.com/fbCH2By8

问题出在服务器上(我可以改进客户端,但当服务器工作时我会这样做)。

我使用这样的 I/O 完成端口:基本上,我运行一个调用 ReadFile() 的线程。如果它返回 TRUE,我得到所有数据,如果它返回 FALSE,并且错误是 ERROR_IO_PENDING,我等待 GetQueuedCompletionStatus()。

奇怪的是,即使我读取了所有数据,最后一次 ReadFile() 调用失败,错误为 ERROR_IO_PENDING

我调用 ReadFile() 的线程在服务器代码的第 64 行开始。

客户端发送 24 个字节(字符串“salut, c'est le client !”)并且 ReadFile() 缓冲区的长度为 5 个字节(检查我的服务器如何处理大于 Readfile() 缓冲区的数据)

输出是:

waiting for client...
WaitForMultipleObjects : 0
client connected (1)
ReadFile 1 msg (5 -> 05) : salut
ReadFile 2 msg (5 -> 10) : salut, c'e
ReadFile 2 msg (5 -> 15) : salut, c'est le
ReadFile 2 msg (5 -> 20) : salut, c'est le clie
ReadFile 2 msg (4 -> 24) : salut, c'est le client !
ReadFile2: ERROR_IO_PENDING
GQCios 0 255 003D3A18
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 4 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING

我不明白的是,即使我读取了所有数据,ReadFile() 仍然返回一个挂起的操作(它是最后一个“msg”输出后的“ReadFile2: ERROR_IO_PENDING”错误消息)

我的循环错了吗?我会误用 ReadFile() / GetQueuedCompletionStatus() 吗?

谢谢

【问题讨论】:

问题似乎是管道的模式。我必须使用消息模式(客户端和服务器),但这无济于事:第一次 ReadFile() 调用失败,读取字节数为 0,错误为 ERROR_MORE_DATA。虽然出现这样的错误是正常的,但前5个字节存储在哪里? 【参考方案1】:

你的写相关函数在哪里?看来您的代码顺序错误。在_read_data_cb 例程中,应首先调用GetQueuedCompletionStatus,然后根据lpOverlapped 参数,接收到的数据应在ReadFile 函数中指定的缓冲区中准备好。由于您在调用 Readfile 时没有检查 OVERLAPPED 是否是发送上下文或接收上下文的重叠结构,因此您没有得到预期的输出。以下代码应该可以解决问题:

while(TRUE)

    bReturnValue=GetQueuedCompletionStatus(pIOCPServer->m_pIOCP, &dwBytesTransferred,(DWORD *)pClient,reinterpret_cast<LPOVERLAPPED*>(&pOverlapped),INFINITE);
    if(!bReturnValue)
    
        if(NULL==pOverlapped)
            continue;
        else
            break;
    
    else
    
        if(pOverlapped==NULL)
            continue;
    
    if(dwBytesTransferred==0)
        break;
    if(lpOverlapped==&(pClient->m_pRecvContext->overlapped))
        pClient->handleRecvEvent(dwBytesTransferred)
    else if(lpOverlapped==&(pClient->m_pSendContext->overlapped))
        pClient->handleSendEvent(dwBytesTransferred)

...

【讨论】:

以上是关于我的循环错了吗?我是不是滥用 ReadFile() 和 I/O 完成端口?的主要内容,如果未能解决你的问题,请参考以下文章

pt-online-schema-change你今天滥用了吗?

C Libevent 未定义的引用,我错了吗?

N 层范式——这个概念错了吗?

缓存,原来我们一直都用错了!

放弃百万年薪,独自创业,我做错了吗?

Windows 中的 ReadFile()