【问题标题】:GetLastError() returns ERROR_BROKEN_PIPE after call to PeekNamedPipe only when using message modeGetLastError() 仅在使用消息模式时调用 PeekNamedPipe 后返回 ERROR_BROKEN_PIPE
【发布时间】:2011-12-28 23:28:28
【问题描述】:

我不知道为什么会这样……我有一个命名管道服务器和客户端应用程序。两者都处于读/写模式并在彼此之间传输数据。服务器有两个线程,一个从管道读取,一个向它写入。当客户端正在写入一堆消息时,服务器的读取线程将退出,因为它对 PeekNamedPipe 的调用返回 false。 GetLastError() 的返回值为 ERROR_BROKEN_PIPE。服务器中的两个线程都没有关闭管道,客户端仍在写入管道,所以我不明白为什么管道“坏了”。

如果我将服务器更改为 BYTE 模式,那么一切都会完美无缺。我真的很想使用消息模式,所以我的“消息”不会组合在一起。

如果我将客户端更改为 BYTE 模式,将服务器更改为消息模式,它可以工作。

调用 CreateNamedPipe

hPipe = CreateNamedPipe(
    pszPipeName,
    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
    PIPE_WAIT | PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE,
    PIPE_UNLIMITED_INSTANCES,
    dwOutBufferSize,
    dwInBufferSize,
    0,
    NULL);

调用 PeekNamedPipe

while( RunningState == DDCMP_STATE_RUNNING )
{
    if( !PeekNamedPipe(hPipe,NULL,NULL,NULL,&dwBytesAvailable,NULL) || !dwBytesAvailable )
        if( GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED || GetLastError() == ERROR_INVALID_HANDLE )
            break;
        else
        {
            Sleep( 100 );
            continue;
        }

    //call to ReadFile(hPipe,...) with dwBytesAvailable as size, and then processing of data
}

【问题讨论】:

  • 你在任何地方打电话给 ConnectNamedPipe 吗?

标签: c++ winapi named-pipes


【解决方案1】:

您不仅在PeekNamedPipe() 失败时调用GetLastError(),而且在它成功并返回0 字节时调用。在后一种情况下,您不应该调用 GetLastError(),因为该值没有意义。改为这样使用它:

while( RunningState == DDCMP_STATE_RUNNING ) 
{ 
    if( !PeekNamedPipe(hPipe, NULL, NULL, NULL, &dwBytesAvailable, NULL) )
    {
        DWORD dwError = GetLastError();

        if( (dwError == ERROR_BROKEN_PIPE) ||
            (dwError == ERROR_PIPE_NOT_CONNECTED) ||
            (dwError == ERROR_INVALID_HANDLE) )
        { 
            break;
        }

        dwBytesAvailable = 0;
    }

    if( !dwBytesAvailable )
    {
        Sleep(100);
        continue;
    }

    //call to ReadFile(hPipe,...) with dwBytesAvailable as size, and then processing of data 
} 

【讨论】:

  • 如果PeekNamedPipe(...)返回true,那么GetLastError()不应该返回ERROR_SUCCESS吗?
  • 这并没有解决问题。 PeekNamedPipe() 正在返回 falseGetLastError() 正在返回 ERROR_PIPE_BROKEN
  • 大多数 API 函数(包括 PeekNamedPipe())不会在成功时更新 GetLastError(),除非它们被明确记录在案(PeekNamedPipe() 没有)。仅当 API 的返回值需要根据上下文进一步说明时,GetLastError() 才会在成功时更新(例如,参见 GetFileSize())。
  • 如果 PeekNamedPipe 返回 false 并且 GetLastError 返回 ERROR_BROKEN_PIPE 那么管道真的消失了。操作系统在内部丢失了连接,或者客户端在您没想到时意外关闭了管道。检查您的客户端代码是否存在类似的逻辑错误,并在您的代码关闭管道时添加一些日志记录,以便您查看谁在执行此操作以及何时执行此操作。
  • 这个答案正是我问你是否打电话给 ConnectNamedPipe 的原因。您似乎正在尝试在客户端连接之前从管道中读取数据。
猜你喜欢
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 2013-03-04
  • 2020-07-02
  • 2016-07-02
  • 2012-01-30
  • 2017-12-21
  • 1970-01-01
相关资源
最近更新 更多