如何使用命名管道客户端/服务器检测客户端断开连接?

时间:2010-03-03 21:58:58

标签: winapi named-pipes disconnect

我正在学习命名管道,并且正在使用来自MSDN doc的命名管道客户端和服务器示例:

Named Pipe Server

Named Pipe Client

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

我的问题是,如果我终止客户端(通过关闭它或通过任务管理器结束它),服务器端是否有办法检测断开连接?

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

  1. 启动了服务器
  2. 启动了客户端
  3. 通过客户端发送消息(点击服务器中的断点)
  4. 杀死了客户端
  5. 逐步进入GetNamedPipeHandleState
  6. 对GetNamedPipeHandleState()的调用成功返回,因此我从未进行过GetLastError()调用。当它到达WriteFileEx调用时它失败并且在那一点上对GetLastError的调用返回ERROR_NO_DATA。

    查看管道功能,我看不到任何可能有用的东西。我遗失了一些东西,或者客户端断开连接只是检测不到。

    我能想到的另一件事就是收集连接客户端的pid(通过GetNamedPipeClientProcessId)并关闭看门狗线程以检查它们是否还活着。但是,只是考虑这样做会引发我的狡猾感。

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

2 个答案:

答案 0 :(得分:5)

ReadFile()不会返回错误而GetLastError()会返回ERROR_BROKEN_PIPE吗?

答案 1 :(得分: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