10

我正在学习命名管道,并正在使用 MSDN 文档中的命名管道客户端和服务器示例:

命名管道服务器

命名管道客户端

我修改了客户端,这样我就可以在控制台中输入消息并将它们发送到服务器,在那里它显示消息并发回回复。本质上,我添加了一个循环,它在 SetNamedPipeHandleState() 调用之后开始并在 CloseHandle() 调用之前结束(即打开和关闭发生在循环之外,所以我在循环中使用相同的管道句柄)。

我的问题是,如果我杀死客户端(通过关闭它或通过任务管理器结束它),服务器端有什么方法可以检测到断开连接?

我尝试过使用 GetNamedPipeHandleState(),希望它返回失败,而对 GetLastError() 的调用将返回 ERROR_PIPE_NOT_CONNECTED,但事实并非如此。由于此服务器的设置方式,我必须在 CompletedReadRoutine 函数中执行此操作并创建“受控”故障。我所做的是,在服务器的 CompletedReadRoutine 上有一个断点:

  1. 启动服务器
  2. 启动客户端
  3. 通过客户端发送消息(在此处命中服务器中的断点)
  4. 杀死客户
  5. 单步执行 GetNamedPipeHandleState

对 GetNamedPipeHandleState() 的调用成功返回,因此我从未进行 GetLastError() 调用。当它到达 WriteFileEx 调用时,它会失败,此时对 GetLastError 的调用会返回 ERROR_NO_DATA。

查看管道功能,我看不到任何其他可能有帮助的东西。我遗漏了一些东西,或者客户端断开连接只是无法检测到。

我能想到的唯一另一件事是收集连接客户端的 pid(通过 GetNamedPipeClientProcessId)并关闭看门狗线程以检查它们是否还活着。不过,一想到这样做就会引起我的蜘蛛侠感。

使用命名管道时有没有办法检测断开连接的客户端?

4

2 回答 2

8

ReadFile()返回和错误GetLastError()然后返回ERROR_BROKEN_PIPE

于 2010-03-04T06:07:41.863 回答
1

ReadFile()+GetLastError()把工作做好。以下是如何将它们与 I/O 完成端口一起使用(我的实现是在 python+ctypes 中,但想法应该很清楚):

def connect():
    GetQueuedCompletionStatus()
    receive()

def receive():
    while True:
        ret_code = ReadFile()
        if ret_code == 0 and GetLastError() == ERROR_BROKEN_PIPE:
            # client disconnected
        GetQueuedCompletionStatus()

我们正在等待完成数据包,当客户端连接时,我们切换到主循环。在主循环中,我们读取管道并通过查看ReadFile()返回码和. 检查客户端是否已断开连接GetLastError()。然后,我们将等待完成数据包。

客户端可以在任何阶段断开连接。完成数据包将排队,我们将得到ERROR_BROKEN_PIPE.

于 2016-06-05T20:09:16.740 回答