使用ReadFile

时间:2018-07-01 23:33:42

标签: windows winapi visual-c++ named-pipes

我想我需要澄清如何从命名管道读取数据并使其立即返回(无论是否有数据)。我所看到的是ReadFile失败,正如预期的那样,但是GetLastError返回ERROR_IO_PENDING或ERROR_PIPE_NOT_CONNECTED,并且这样做直到周围的代码超时。即使收到的数据确实存在,我也会收到这些错误。我通过检查读取缓冲区并查看期望值来了解这一点。而且管道一直在工作。我怀疑我没有正确使用重叠结构,只是将所有字段设置为零。我的代码如下:

gPipe = CreateFile(gPipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
pMode = PIPE_READMODE_MESSAGE; 
bret = SetNamedPipeHandleState(gPipe, &pMode, NULL, NULL);

OVERLAPPED ol;
memset(&ol, 0, sizeof(OVERLAPPED));

// the following inside a loop that times out after a period
bret = ReadFile(gPipe, &tmostat, sizeof(TMO64STAT), NULL, &ol);
if (bret) break;
err = GetLastError();
// seeing err == ERROR_IO_PENDING or ERROR_PIPE_NOT_CONNECTED

因此,我可以通过忽略错误并检查到达的数据来做我想做的事情,但这很困扰我。知道为什么我会出现这种行为吗?

1 个答案:

答案 0 :(得分:1)

Windows OVERLAPPED I / O不能像其他操作系统上的非阻塞标志一样工作(例如,在Linux上,最接近的等效项是aio_*() API,而不是FIONBIO

使用OVERLAPPED I / O,操作没有失败,它在后台进行。但是您永远不会检查它……您只需再试一次。有许多待处理的操作,您总是在开始新的操作,而从不检查旧的操作。

填写OVERLAPPED结构的hEvent字段,并用它来检测操作何时完成。然后调用GetOverlappedResult()以获取实际传输的字节数。

另一个重要说明-操作系统拥有OVERLAPPED结构和缓冲区,直到操作完成为止,您必须注意确保它们保持有效,并且不要取消分配它们或将其用于任何其他操作,除非您确认第一个操作完成。


请注意,Win32管道有实际的非阻塞模式,但是Microsoft强烈建议您不要使用它:

  

支持非阻塞等待模式以与Microsoft LAN Manager 2.0版兼容。此模式不应用于与命名管道实现重叠的输入和输出(I / O)。相反,应该使用重叠的I / O,因为它可以使耗时的操作在函数返回后在后台运行。