Windows命名管道问题:错误代码233交替出现

10
我需要帮助我的应用程序。这是一个简单的程序,响应命令行参数。如果第一次调用应用程序,它将在专门的另一个线程上启动为管道服务器(阻塞、非重叠),而主线程则执行其他操作。现在,用户仍然可以使用相同的应用程序可执行文件和命令行参数调用应用程序,但由于它不是应用程序的第一个实例,它会通过管道将命令行参数传递给第一个实例,然后结束自身。因此,它就像一种模式语言中的单例进程。
理想情况下,应该是这样的:
app.exe "first"    // starts app.exe as a pipe server and prints "first"
app.exe "second"   // client process causes server instance to print "second"
app.exe "third"    // client process causes server instance to print "third"
app.exe "fourth"   // client process causes server instance to print "fourth"
app.exe "fifth"    // client process causes server instance to print "fifth"
app.exe -quit      // client process causes server instance to terminate.

现在,我唯一的问题是,当我执行上述代码时会发生以下情况:

app.exe "first"    // starts app.exe as a pipe server and prints "first"
app.exe "second"   // client process returns a GetLastError code of 233
app.exe "third"    // client process causes server instance to print "third"
app.exe "fourth"   // client process returns a GetLastError code of 233
app.exe "fifth"    // client process causes server instance to print "fifth"
app.exe -quit      // client process returns a GetLastError code of 233

我的管道服务器代码大致如下(伪代码):

CreateNamedPipe();
// Code below now runs on a separate thread...
while( !Quit )
{
    if( ConnectNamedPipe() is successful )
    {
        if( PeekNamedPipe() has a message )
        {
            ReadFile();
            ProcessReceivedMessage();
        }
        FileFlushBuffers();
        DisconnectNamedPipe();
    }
}
CloseHandle( the pipe );

我的客户端版本如下(伪代码):

if( WaitNamedPipe( FOREVER ) != 0 )
{
    GetParametersAndFormAMessage();
    CreateFile();
    WriteFile(); // Sends message to the pipe server
}
CloseHandle();

根据MSDN文档,如果服务器使用DisconnectNamedPipe()方法,客户端将被强制断开连接,并在下一次尝试连接时收到错误。你认为这是原因吗?如果是,那么我如何在不出现额外错误的情况下断开客户端的连接呢?否则,还有什么需要我知道的来使这个工作?我花了很多时间来解决这个问题。

1个回答

19

为了避免出现“ERROR_PIPE_NOT_CONNECTED”错误,你应该在每个客户端实例的服务器端使用一个不同的管道实例进行通信,并为每个线程使用单独的线程。因此,当ConnectNamedPipe()返回时,立即启动一个新的侦听线程以等待下一个客户端,然后再处理刚连接的客户端的消息。

然后,每个客户端将通过一个新创建的管道实例进行通信,你将不会看到ERROR_PIPE_NOT_CONNECTED错误。

假设伪代码如下:

Main Thread
{
    CreateListenerThread();
    WaitForQuitEvent();
}

ListenerThread
{
    ConnectNamedPipe();
    if (no error)
    {
        CreateListenerThread();
        if( PeekNamedPipe() has a message )
        {
            ReadFile();
            ProcessReceivedMessage(); // if -quit signal quit event
        }
        FileFlushBuffers();
        DisconnectNamedPipe();
        CloseHandle();
    }
    else
    {
        // handle/report error
    }
}

这意味着你有一个线程没有连接(因为每个连接的线程都会生成一个新的线程),并且只是等待客户端连接。如何确保该线程在执行完成后得到适当的清理? - Tam Coton
@TamCoton ConnectNamedPipe 步骤应该包括一个相当短的超时时间,以便它定期取消阻塞以检查终止条件,例如像 if(shouldQuit) return 这样的标志。 - dss539
1
这不可能是最好的(“正确的”)答案。生成一个新线程是一项昂贵的操作;我无法想象Windows NT被设计为在处理连续连接请求时需要每次都进行线程生成。 - user1254127

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接