Mike Trader
Mike Trader

Reputation: 8704

Synchronizing reading and writing with synchronous NamedPipes

A Named Pipe Server is created with

hPipe = CreateNamedPipe( zPipePath,
                         PIPE_ACCESS_DUPLEX,
                         PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_READMODE_BYTE,
                         PIPE_UNLIMITED_INSTANCES,
                         8192, 8192, NMPWAIT_USE_DEFAULT_WAIT, NULL)

Then we immediately call:

ConnectNamedPipe( hPipe, BYVAL %NULL )

Which blocks until the client connects.

Then we proceed directly to ReadFile( hPipe, ...

The problem is that it takes the Client takes a finite amount of time to prepare and write all the fcgi request parameters. This has usually not completed before the Pipe Server performs its ReadFile(). The Read file operation thus finds no data in the pipe and the process fails.

Is there a mechanism to tell when a Write() has occurred/finished after a client has connected to a NamedPipe?

If I had control of the Client process, I could use a common Mutex, but I don't, and I really do not want to get into I/O completion ports just to solve this problem!

I can of course use a simple timer to wait 60m/s or so which is usually plenty of time for the write to complete, but that is a horrible hack.

Upvotes: 1

Views: 5207

Answers (1)

Michael Burr
Michael Burr

Reputation: 340218

I'm not sure what language you're using - I don't recognize the expression like

PIPE_TYPE_BYTE OR %PIPE_WAIT OR %PIPE_READMODE_BYTE

but it looks like to me that the server's ReadFile() should block until data is written by the client.

One thing that doesn't look right (but shouldn't be hurting anything) is the use of NMPWAIT_USE_DEFAULT_WAIT - that value is intended for a client's use when calling WaitNamedPipe().

Could you see if these 2 C++ programs interact like you expect (ie., with the server blocking until the client writes something)? I took these programs from the Jones/Ohlund book "Network Programming for Windows" The server blocks in the ReadFile() call for me as expected:

- server.cpp

// Server.cpp

#include <windows.h>
#include <stdio.h>

void main(void)
{
    HANDLE PipeHandle;
    DWORD BytesRead;
    CHAR buffer[256];
    if ((PipeHandle = CreateNamedPipe("\\\\.\\Pipe\\Jim",
        PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1,
        0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)
    {
        printf("CreateNamedPipe failed with error %d\n",
            GetLastError());
        return;
    }

    printf("Server is now running\n");

    if (ConnectNamedPipe(PipeHandle, NULL) == 0)
    {
        printf("ConnectNamedPipe failed with error %d\n",
            GetLastError());
        CloseHandle(PipeHandle);
        return;
    }

    if (ReadFile(PipeHandle, buffer, sizeof(buffer),
        &BytesRead,  NULL) <= 0)
    {
        printf("ReadFile failed with error %d\n", GetLastError());
        CloseHandle(PipeHandle);
        return;
    }

    printf("%.*s\n", BytesRead, buffer);

    if (DisconnectNamedPipe(PipeHandle) == 0)
    {
        printf("DisconnectNamedPipe failed with error %d\n",
            GetLastError());
        return;
    }

    CloseHandle(PipeHandle);
}

- client.cpp

// Client.cpp

#include <windows.h>
#include <stdio.h>

#define PIPE_NAME "\\\\.\\Pipe\\jim"

void main(void)
{
    HANDLE PipeHandle;
    DWORD BytesWritten;

    if (WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER) == 0)
    {
        printf("WaitNamedPipe failed with error %d\n",
            GetLastError());
        return;
    }

    // Create the named pipe file handle
    if ((PipeHandle = CreateFile(PIPE_NAME,
        GENERIC_READ | GENERIC_WRITE, 0,
        (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        (HANDLE) NULL)) == INVALID_HANDLE_VALUE)
    {
        printf("CreateFile failed with error %d\n", GetLastError());
        return;
    }

    if (WriteFile(PipeHandle, "This is a test", 14, &BytesWritten, 
        NULL) == 0)
    {
        printf("WriteFile failed with error %d\n", GetLastError());
        CloseHandle(PipeHandle);
        return;
    }

    printf("Wrote %d bytes", BytesWritten);

    CloseHandle(PipeHandle);
}

Upvotes: 4

Related Questions