简体   繁体   中英

how to make client to check if the server is done with read operation from pipe before writing data into pipe in c++

I need my client to first check if server is reading data from pipe, if yes then wait till server is done else write data into pipe. If I don't use sleep command in my sample client program then Server doesn't read message properly.I found the reason of this issue from the documentation it says:

This buffer must remain valid for the duration of the read operation. The caller must not use this buffer until the read operation is completed.

But it doesn't specify how to block client until the read operation is complete.

Server Code:

#include<stdio.h>
#include<windows.h>
#include<iostream>
using namespace std;
int main(void)
{
    HANDLE hPipe;
    char buffer[1024];
    DWORD dwRead;


hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
                        PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
                        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
                        1,
                        1024 * 16,
                        1024 * 16,
                        NMPWAIT_USE_DEFAULT_WAIT,
                        NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
    if (ConnectNamedPipe(hPipe, NULL) != FALSE)   // wait for someone to connect to the pipe
    {
        while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
        {
            /* add terminating zero */
            buffer[dwRead] = '\0';

            /* do something with data in buffer */
            printf("%s", buffer);
        }
    }

    DisconnectNamedPipe(hPipe);
}

return 0;

}

Client Code:

#include<stdio.h>
#include<windows.h>
#include<iostream>
#include<stdlib.h> 
using namespace std;
void fun()
{
     HANDLE hPipe;
    DWORD dwWritten;


    hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), 
                       GENERIC_WRITE, 
                       0,
                       NULL,
                       OPEN_EXISTING,
                       0,
                       NULL);
    if (hPipe != INVALID_HANDLE_VALUE)
    {
        WriteFile(hPipe,
                  "Hello Pipe",
                  11,   // = length of string + terminating '\0' !!!
                  &dwWritten,
                  NULL);

        CloseHandle(hPipe);
    }

}
int main(void)
{
   int a = 5;
   cout<<a;
   for(int i = 0; i<a; i++)
   {
    fun();
    Sleep(2000);
   }

    return (0);
}

This is just a sample program, actually my client is a very big application it has many functions and I don't want to make any major changes in it. Whenever a particular function gets triggered it should pass data to server. The type of data is a structure. After receiving data in server I want to write that data into text file (After converting it into json format).

So how can I make my client to check if the server is done reading data from pipe before writing data into pipe? Client should not wait forever for the server as it will affect my client application. It should wait for a specified time interval. Also to pass structure which pipe mode should I use BYTE MODE or MESSAGE MODE?

main error in next line of server code

if (ConnectNamedPipe(hPipe, NULL) != FALSE)

here we assume that if ConnectNamedPipe return FALSE it fail. but this is not true even for synchronous pipe handle:

Otherwise, ConnectNamedPipe returns zero, and GetLastError returns ERROR_NO_DATA if the previous client has closed its handle or ERROR_PIPE_CONNECTED if it has not closed its handle.

client can connect (call CreateFile ) after server call CreateNamedPipeW but before call ConnectNamedPipe . exactly in this case driver( npfs ) can return 2 status on FSCTL_PIPE_LISTEN ( ConnectNamedPipe ) request:

  1. STATUS_PIPE_CONNECTED (translated to ERROR_PIPE_CONNECTED ) if client already connect (before FSCTL_PIPE_LISTEN ) and yet not close own handle)
  2. STATUS_PIPE_CLOSING (translated to ERROR_NO_DATA ) client has closed its handle. but he can call WriteFile before this and some data in pipe actually exist.

also use NMPWAIT_USE_DEFAULT_WAIT in call CreateNamedPipeW - here must be actual timeout. this constant used in call WaitNamedPipeW instead.

the synchronous pipe client/server can be tested by next code. (of course much better use asynchronous i/o)

ULONG WINAPI ct(void* name)
{
    if (WaitNamedPipeW((PCWSTR)name, NMPWAIT_USE_DEFAULT_WAIT))
    {
        MessageBoxW(0, 0, L"client delay #1", 0);// for debug

        HANDLE hPipe = CreateFileW((PCWSTR)name, 
            GENERIC_WRITE, 
            0,
            NULL,
            OPEN_EXISTING,
            0,
            NULL);

        if (hPipe != INVALID_HANDLE_VALUE)
        {
            static WCHAR str[] = L"Hello Pipe";

            DWORD dwWritten;

            WriteFile(hPipe, str,
                sizeof(str),
                &dwWritten,
                NULL);

            MessageBoxW(0, 0, L"client delay #2", 0);// for debug

            CloseHandle(hPipe);
        }
    }

    return GetLastError();
}

void sc()
{
    char buffer[1024];

    static WCHAR name[] = L"\\\\.\\pipe\\Pipe";

    HANDLE hPipe = CreateNamedPipeW(name,
        PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        1,
        1024 * 16,
        1024 * 16,
        INFINITE,
        NULL);

    if (hPipe != INVALID_HANDLE_VALUE)
    {
        int n = 2;
        do
        {
            CloseHandle(CreateThread(0, 0, ct, name, 0, 0));
            MessageBoxW(0, 0, L"Server delay", 0);// for debug

            switch (ConnectNamedPipe(hPipe, NULL) ? NOERROR : GetLastError())
            {
            case NOERROR:
            case ERROR_PIPE_CONNECTED: // STATUS_PIPE_CONNECTED
            case ERROR_NO_DATA: // STATUS_PIPE_CLOSING

                DWORD dwRead;
                while (ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL))
                {
                    /* do something with data in buffer */
                    printf("%.*S", dwRead, buffer);
                }

                DisconnectNamedPipe(hPipe);
                break;
            }
        } while (--n);

        CloseHandle(hPipe);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM