Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect a client disconnect using a named pipe client/server?

I'm learning about named pipes and was playing with the named pipe client and server examples from the MSDN doc:

Named Pipe Server

Named Pipe Client

I modified the client so I can type in messages to the console and have them sent to the server where it displays the message and sends back a reply. Essentially I added a loop which starts after the SetNamedPipeHandleState() call and ends before the CloseHandle() call (i.e. the open and close happen outside the loop, so I am using the same pipe handle within the loop).

My question is, if I kill the client (by closing it or ending it via Task Manager) is there any way for the server side to detect the disconnect?

I've tried using GetNamedPipeHandleState() hoping it return failure and a call to GetLastError() would return ERROR_PIPE_NOT_CONNECTED, but that was not the case. Because of the way this server is set up I had to do this in the CompletedReadRoutine function and create a "controlled" failure. What I did was, with a breakpoint on the CompletedReadRoutine in the server:

  1. started the server
  2. started the client
  3. sent a message via the client (hits the breakpoint in the server here)
  4. killed the client
  5. Stepped through to the GetNamedPipeHandleState

The call to GetNamedPipeHandleState() returns successfully so I never got to do the GetLastError() call. When it gets to the WriteFileEx call it fails and a call to GetLastError at that point returns an ERROR_NO_DATA.

Looking at the pipe functions I can't see anything else that would possibly help here. I am missing something or is a client disconnect just not detectable.

The only other thing I can think of is collecting the pid's of the connecting clients (via GetNamedPipeClientProcessId) and spinning off watchdog threads to check if they are still alive. Though, just thinking about doing that sets off my spidey sense.

Is there a way to detect disconnected clients when using named pipes?

like image 317
Robert Groves Avatar asked Mar 03 '10 21:03

Robert Groves


2 Answers

Doesn't ReadFile() return and error and GetLastError() then return ERROR_BROKEN_PIPE?

like image 101
Len Holgate Avatar answered Oct 09 '22 02:10

Len Holgate


ReadFile() + GetLastError() do the job well. Here is how they can be used with I/O Completion Ports (my implementation is in python+ctypes, but the idea should be clear):

def connect():
    GetQueuedCompletionStatus()
    receive()

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

We are waiting for a completion packet, and when a client connects, we switch to the main loop. In the main loop we read the pipe and check if the client has disconnected by looking at ReadFile() return code and GetLastError(). Then again, we will wait for a completion packet.

A client can disconnect on any stage. Completion packet will be queued and we will get ERROR_BROKEN_PIPE.

like image 42
wombatonfire Avatar answered Oct 09 '22 00:10

wombatonfire