< Multithreaded & Overlapped Server Examples | Name Pipes Main | Completion Routines Server Example >


 

 

Named Pipes 15 Part 5

 

 

What do we have in this chapter 15 part 5?

  1. Another Named Pipe Server Using Overlapped I/O

  2. Name Pipe Client Example 3

 

Another Named Pipe Server Using Overlapped I/O

 

Create a new empty Win32 console mode application and add the project/solution name.

 

Winsock: The Named Pipe Server Using Overlapped I/O Example

 

Add the following source code.

 

#include <windows.h>

#include <stdio.h>

// Generic-Text Mappings which are Microsoft extensions

// that are not ANSI compatible. However those related

// string/text functions can be 'ported'/migrated easily to ANSI

// http://msdn.microsoft.com/en-us/library/c426s321.aspx

#include <tchar.h>

// Using a safer string manipulation/processing functions

// http://msdn.microsoft.com/en-us/library/ms647466.aspx

#include <strsafe.h>

 

// Constants

#define CONNECTING_STATE 0

#define READING_STATE 1

#define WRITING_STATE 2

#define INSTANCES 4

#define PIPE_TIMEOUT 500

#define BUFSIZE 4096

 

typedef struct

{

   OVERLAPPED oOverlap;

   HANDLE hPipeInst;

   TCHAR chRequest[BUFSIZE];

   DWORD cbRead;

   TCHAR chReply[BUFSIZE];

   DWORD cbToWrite;

   DWORD dwState;

   BOOL fPendingIO;

} PIPEINST, *LPPIPEINST;

 

// Prototypes

VOID DisconnectAndReconnect(DWORD);

BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);

VOID GetAnswerToRequest(LPPIPEINST);

 

PIPEINST Pipe[INSTANCES];

HANDLE hEvents[INSTANCES];

 

int _tmain(int argc, TCHAR **argv)

{

            DWORD i, dwWait, cbRet, dwErr;

            BOOL fSuccess;

            LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\pipebodo");

 

            // The initial loop creates several instances of a named pipe

            // along with an event object for each instance.  An

            // overlapped ConnectNamedPipe operation is started for each instance

            for (i = 0; i < INSTANCES; i++)

            {

                        // Create an event object for this instance

                        hEvents[i] = CreateEvent(

                                    NULL,    // default security attribute

                                    TRUE,    // manual-reset event

                                    TRUE,    // initial state = signaled

                                    NULL);   // unnamed event object

                        if (hEvents[i] == NULL)

                        {

                                    printf("CreateEvent() failed with error code %d.\n", GetLastError());

                                    return 0;

                        }

                        else

                                    printf("CreateEvent() should be fine!\n");

 

                        Pipe[i].oOverlap.hEvent = hEvents[i];

                        Pipe[i].hPipeInst = CreateNamedPipe(

                                    lpszPipename,            // pipe name

                                    PIPE_ACCESS_DUPLEX |     // read/write access

                                    FILE_FLAG_OVERLAPPED,    // overlapped mode

                                    PIPE_TYPE_MESSAGE |      // message-type pipe

                                    PIPE_READMODE_MESSAGE |  // message-read mode

                                    PIPE_WAIT,               // blocking mode

                                    INSTANCES,               // number of instances

                                    BUFSIZE*sizeof(TCHAR),   // output buffer size

                                    BUFSIZE*sizeof(TCHAR),   // input buffer size

                                    PIPE_TIMEOUT,            // client time-out

                                    NULL);                   // default security attributes

 

                        if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)

                        {

                                    printf("CreateNamedPipe() failed with error code %d.\n", GetLastError());

                                    return 0;

                        }

 

                        // Call the subroutine to connect to the new client

                        Pipe[i].fPendingIO = ConnectToNewClient(Pipe[i].hPipeInst, &Pipe[i].oOverlap);

 

                        Pipe[i].dwState = Pipe[i].fPendingIO ? CONNECTING_STATE : // still connecting

                                    READING_STATE;     // ready to read

            }

 

            while (1)

            {

                        // Wait for the event object to be signaled, indicating

                        // completion of an overlapped read, write, or connect operation

                        dwWait = WaitForMultipleObjects(

                                    INSTANCES,    // number of event objects

                                    hEvents,      // array of event objects

                                    FALSE,        // does not wait for all

                                    INFINITE);    // waits indefinitely

 

                        // dwWait shows which pipe completed the operation

                        i = dwWait - WAIT_OBJECT_0;  // determines which pipe

                        if (i < 0 || i > (INSTANCES - 1))

                        {

                                    printf("Index is out of range!\n");

                                    return 0;

                        }

                        // Get the result if the operation was pending

                        if (Pipe[i].fPendingIO)

                        {

                                    fSuccess = GetOverlappedResult(

                                                Pipe[i].hPipeInst,         // handle to pipe

                                                &Pipe[i].oOverlap,      // OVERLAPPED structure

                                                &cbRet,                        // bytes transferred

                                                FALSE);                       // do not wait

                                    switch (Pipe[i].dwState)

                                    {

                                    // Pending connect operation

                                    case CONNECTING_STATE:

                                                if (!fSuccess)

                                                {

                                                            printf("Error %d lor!\n", GetLastError());

                                                            return 0;

                                                }

                                                Pipe[i].dwState = READING_STATE;

                                                break;

                                    // Pending read operation

                                    case READING_STATE:

                                                if (! fSuccess || cbRet == 0)

                                                {

                                                            DisconnectAndReconnect(i);

                                                            continue;

                                                }

                                                Pipe[i].dwState = WRITING_STATE;

                                                break;

 

                                    // Pending write operation

                                    case WRITING_STATE:

                                                if (! fSuccess || cbRet != Pipe[i].cbToWrite)

                                                {

                                                            DisconnectAndReconnect(i);

                                                            continue;

                                                }

                                                Pipe[i].dwState = READING_STATE;

                                                break;

                                    default:

                                                {

                                                            printf("Invalid pipe state!\n");

                                                            return 0;

                                                }

                                    }

                        }

 

                        // The pipe state determines which operation to do next

                        switch (Pipe[i].dwState)

                        {

                                    // READING_STATE:

                                    // The pipe instance is connected to the client

                                    // and is ready to read a request from the client

                        case READING_STATE:

                                    fSuccess = ReadFile(Pipe[i].hPipeInst, Pipe[i].chRequest, BUFSIZE*sizeof(TCHAR), &Pipe[i].cbRead, &Pipe[i].oOverlap);

                                    // The read operation completed successfully

                                    if (fSuccess && Pipe[i].cbRead != 0)

                                    {

                                                printf("Read operation completed successfully!\n");

                                                Pipe[i].fPendingIO = FALSE;

                                                Pipe[i].dwState = WRITING_STATE;

                                                continue;

                                    }

                                    // The read operation is still pending

                                    dwErr = GetLastError();

                                    if (! fSuccess && (dwErr == ERROR_IO_PENDING))

                                    {

                                                printf("read operation is still pending!\n");

                                                Pipe[i].fPendingIO = TRUE;

                                                continue;

                                    }

 

                                    // An error occurred; disconnect from the client

                                    DisconnectAndReconnect(i);

                                    break;

 

                                    // WRITING_STATE:

                                    // The request was successfully read from the client

                                    // Get the reply data and write it to the client

                        case WRITING_STATE:

                                    GetAnswerToRequest(&Pipe[i]);

                                    fSuccess = WriteFile(

                                                Pipe[i].hPipeInst,

                                                Pipe[i].chReply,

                                                Pipe[i].cbToWrite,

                                                &cbRet,

                                                &Pipe[i].oOverlap);

 

                                    // The write operation completed successfully

                                    if (fSuccess && cbRet == Pipe[i].cbToWrite)

                                    {

                                                printf("Write operation completed successfully!\n");

                                                Pipe[i].fPendingIO = FALSE;

                                                Pipe[i].dwState = READING_STATE;

                                                continue;

                                    }

 

                                    // The write operation is still pending

                                    dwErr = GetLastError();

                                    if (! fSuccess && (dwErr == ERROR_IO_PENDING))

                                    {

                                                printf("write operation is still pending!\n");

                                                Pipe[i].fPendingIO = TRUE;

                                                continue;

                                    }

 

                                    // An error occurred; disconnect from the client

                                    DisconnectAndReconnect(i);

                                    break;

                        default:

                                    {

                                                printf("Invalid pipe state!\n");

                                                return 0;

                                    }

                        }

}

return 0;

}

 

// DisconnectAndReconnect(DWORD)

// This function is called when an error occurs or when the client

// closes its handle to the pipe. Disconnect from this client, then

// call ConnectNamedPipe to wait for another client to connect

VOID DisconnectAndReconnect(DWORD i)

{

            // Disconnect the pipe instance

            if (!DisconnectNamedPipe(Pipe[i].hPipeInst) )

            {

                        printf("DisconnectNamedPipe() failed with error code %d.\n", GetLastError());

            }

            else

                        printf("DisconnectNamedPipe() should be OK!\n");

            // Call a subroutine to connect to the new client

            Pipe[i].fPendingIO = ConnectToNewClient(Pipe[i].hPipeInst, &Pipe[i].oOverlap);

            Pipe[i].dwState = Pipe[i].fPendingIO ? CONNECTING_STATE : // still connecting

                        READING_STATE;     // ready to read

}

 

// ConnectToNewClient(HANDLE, LPOVERLAPPED)

// This function is called to start an overlapped connect operation

// It returns TRUE if an operation is pending or FALSE if the connection has been completed

BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)

{

            BOOL fConnected, fPendingIO = FALSE;

            // Start an overlapped connection for this pipe instance

            fConnected = ConnectNamedPipe(hPipe, lpo);

            // Overlapped ConnectNamedPipe should return zero

            if (fConnected)

            {

                        printf("ConnectNamedPipe() failed with error code %d.\n", GetLastError());

                        return 0;

            }

            else

                        printf("ConnectNamedPipe() is OK!\n");

 

            switch (GetLastError())

            {

            // The overlapped connection in progress

            case ERROR_IO_PENDING:

                        fPendingIO = TRUE;

                        break;

            // Client is already connected, so signal an event

            case ERROR_PIPE_CONNECTED:

                        if (SetEvent(lpo->hEvent))

                                    break;

            // If an error occurs during the connect operation...

            default:

                        {

                                    printf("ConnectNamedPipe() failed with error code %d.\n", GetLastError());

                                    return 0;

                        }

            }

   return fPendingIO;

}

 

VOID GetAnswerToRequest(LPPIPEINST pipe)

{

   _tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);

   StringCchCopy( pipe->chReply, BUFSIZE, TEXT(" \"Default answer from server\"") );

   pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);

}

 

Build and run the project.

 

----------------------------------------------------

Named Pipe Server Using Overlapped I/O sample console output

 

Name Pipe Client Example 3

 

Create a new empty Win32 console mode application and add the project/solution name.

 

Winsock: Named Pipe Server Using Overlapped I/O - Name Pipe Client Example 3

 

Add the following source code.

 

#include <windows.h>

#include <stdio.h>

// Generic-Text Mappings which are Microsoft extensions

// that are not ANSI compatible. However those related

// string/text functions can be 'ported'/migrated easily to ANSI

// http://msdn.microsoft.com/en-us/library/c426s321.aspx

#include <tchar.h>

 

#define BUFSIZE 512

 

int _tmain(int argc, TCHAR *argv[])

{

            HANDLE hPipe;

            LPTSTR lpvMessage=TEXT(" \"Default message from client\"");

            TCHAR chBuf[BUFSIZE];

            BOOL fSuccess;

            DWORD cbRead, cbWritten, dwMode;

            LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\pipebodo");

 

            if(argc > 1)

                        lpvMessage = argv[1];

            else

            {

                        printf("Usage: %S <message to send>\n", argv[0]);

                        printf("Example: %S \"Some test message\"\n", argv[0]);

            }

 

            // Try to open a named pipe; wait for it, if necessary

            while (1)

            {

                        hPipe = CreateFile(

                                    lpszPipename,   // pipe name

                                    GENERIC_READ |  // read and write access

                                    GENERIC_WRITE,

                                    0,              // no sharing

                                    NULL,           // default security attribute

                                    OPEN_EXISTING,  // opens existing pipe

                                    0,              // default attributes

                                    NULL);          // no template file

 

                        // Break if the pipe handle is valid

                        if (hPipe != INVALID_HANDLE_VALUE)

                                    break;

 

                        // Exit if an error other than ERROR_PIPE_BUSY occurs

                        if (GetLastError() != ERROR_PIPE_BUSY)

                        {

                                    printf("Could not open pipe!");

                                    return 0;

                        }

 

                        // All pipe instances are busy, so wait for 20 seconds

                        if (!WaitNamedPipe(lpszPipename, 20000))

                        {

                                    printf("Could not open pipe!");

                                    return 0;

                        }

                        printf("pipe was opened and connected successfully!\n");

            }

 

            // The pipe connected; change to message-read mode

            dwMode = PIPE_READMODE_MESSAGE;

            fSuccess = SetNamedPipeHandleState(

                        hPipe,    // pipe handle

                        &dwMode,  // new pipe mode

                        NULL,     // don't set maximum bytes

                        NULL);    // don't set maximum time

            if (!fSuccess)

            {

                        printf("SetNamedPipeHandleState() failed with error code %d", GetLastError());

                        return 0;

            }

            else

                        printf("SetNamedPipeHandleState() is OK!\n");

 

            // Send a message to the pipe server

            fSuccess = WriteFile(

                        hPipe,                  // pipe handle

                        lpvMessage,             // message

                        (lstrlen(lpvMessage)+1)*sizeof(TCHAR), // message length

                        &cbWritten,             // bytes written

                        NULL);                  // not overlapped

            if (!fSuccess)

            {

                        printf("WriteFile() failed with error code %d\n", GetLastError());

                        return 0;

            }

            else

                        printf("WriteFile() is fine!\n");

 

            do

            {

                        // Read from the pipe

                        fSuccess = ReadFile(

                                    hPipe,    // pipe handle

                                    chBuf,    // buffer to receive reply

                                    BUFSIZE*sizeof(TCHAR),  // size of buffer

                                    &cbRead,  // number of bytes read

                                    NULL);    // not overlapped

 

                        if (! fSuccess && GetLastError() != ERROR_MORE_DATA)

                                    break;

                        _tprintf( TEXT("%s\n"), chBuf );

            } while (!fSuccess);  // repeat loop if ERROR_MORE_DATA

 

            if(CloseHandle(hPipe) != 0)

                        printf("hPipe handle closed successfully!\n");

            else

                        printf("Failed to close hFile handle, error code %d\n", GetLastError());

 

            return 0;

}

 

Build and run the project.

 

Winsock: Named Pipe Server Using Overlapped I/O - Name Pipe Client sample output

 

Let test this client with the previous server program. Firstly we run the server program.

 

Winsock: Named Pipe Server Using Overlapped I/O - Name Pipe Client Example 3 sample server output

 

Next we run the client program twice.

 

Winsock: Named Pipe Server Using Overlapped I/O - Name Pipe Client Example 3 testing the client with the server

 

The previous server sample output is shown below.

 

Winsock: Named Pipe Server Using Overlapped I/O - Name Pipe Client Example 3, the server output when communication was completed

 

 

 


< Multithreaded & Overlapped Server Examples | Name Pipes Main | Completion Routines Server Example >