< Name Pipes APIs & Client Program Example | Name Pipes Main | Overlapped I/O Server & Client Examples >


 

 

Named Pipes 15 Part 4

 

 

What do we have in this chapter 15 part 4?

  1. The Name Pipe Overlapped Server Example

  2. Multithreaded Pipe Server Example

 

The Name Pipe Overlapped Server Example

 

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

 

Winsock: The Name Pipe Overlapped Server Program Example

 

Add the following source code.

 

// Purpose:

//     This sample demonstrates how to develop an advanced named

//     pipe server that is capable of servicing 5 named pipe

//     instances. The application is an echo server where data is

//     received from a client and echoed back to the client. All

//     the pipe instances are serviced in the main application

//     thread using Win32 overlapped I/O.

//

// Command line options: None

//

#include <windows.h>

#include <stdio.h>

 

#define NUM_PIPES 5

#define BUFFER_SIZE 256

 

void main(void)

{

            HANDLE PipeHandles[NUM_PIPES];

            DWORD BytesTransferred;

            CHAR Buffer[NUM_PIPES][BUFFER_SIZE];

            INT i;

            OVERLAPPED Ovlap[NUM_PIPES];

            HANDLE Event[NUM_PIPES];

 

            // For each pipe handle instance, the code must maintain the

            // pipes' current state, which determines if a ReadFile or

            // WriteFile is posted on the named pipe. This is done using

            // the DataRead variable array. By knowing each pipe's

            // current state, the code can determine what the next I/O operation should be.

            BOOL DataRead[NUM_PIPES];

            DWORD Ret;

            DWORD Pipe;

 

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

            {

                        // Create a named pipe instance

                        if ((PipeHandles[i] = CreateNamedPipe(L"\\\\.\\Pipe\\jim",

                                    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,

                                    PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, NUM_PIPES,

                                    0, 0, 1000, NULL)) == INVALID_HANDLE_VALUE)

                        {

                                    printf("CreateNamedPipe() for pipe %d failed with error %d\n", i, GetLastError());

                                    return;

                        }

                        else

                                    printf("CreateNamedPipe() for pipe %d is OK!\n", i);

 

                        // Create an event handle for each pipe instance. This

                        // will be used to monitor overlapped I/O activity on each pipe

                        if ((Event[i] = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)

                        {

                                    printf("CreateEvent() for pipe %d failed with error %d\n",  i, GetLastError());

                                    continue;

                        }

                        else

                                    printf("CreateEvent() for pipe %d is OK!\n", i);

 

                        // Maintain a state flag for each pipe to determine when data is to be read from or written to the pipe

                        DataRead[i] = FALSE;

                        ZeroMemory(&Ovlap[i], sizeof(OVERLAPPED));

                        Ovlap[i].hEvent = Event[i];

 

                        // Listen for client connections using ConnectNamedPipe()

                        if (ConnectNamedPipe(PipeHandles[i], &Ovlap[i]) == 0)

                        {

                                    if (GetLastError() != ERROR_IO_PENDING)

                                    {

                                                printf("ConnectNamedPipe() for pipe %d failed with error %d\n", i, GetLastError());

                                                printf("Closing handle...\n");

                                                CloseHandle(PipeHandles[i]);

                                                return;

                                    }

                        }

                        else

                                    printf("ConnectNamedPipe() for pipe %d is OK!\n", i);

            }

 

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

 

            // Read and echo data back to Named Pipe clients forever

            while(1)

            {

                        if ((Ret = WaitForMultipleObjects(NUM_PIPES, Event, FALSE, INFINITE)) == WAIT_FAILED)

                        {

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

                                    return;

                        }

                        else

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

 

                        Pipe = Ret - WAIT_OBJECT_0;

                        ResetEvent(Event[Pipe]);

 

                        // Check overlapped results, and if they fail, reestablish

                        // communication for a new client; otherwise, process read and write operations with the client

                        if (GetOverlappedResult(PipeHandles[Pipe], &Ovlap[Pipe], &BytesTransferred, TRUE) == 0)

                        {

                                    printf("GetOverlapped() result failed %d start over...\n", GetLastError());

                                    if (DisconnectNamedPipe(PipeHandles[Pipe]) == 0)

                                    {

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

                                                return;

                                    }

                                    else

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

 

                                    if (ConnectNamedPipe(PipeHandles[Pipe],  &Ovlap[Pipe]) == 0)

                                    {

                                                if (GetLastError() != ERROR_IO_PENDING)

                                                {

                                                            // Severe error on pipe. Close this handle forever

                                                            printf("ConnectNamedPipe() for pipe %d failed with error %d\n", i, GetLastError());

                                                            printf("Closing handle...\n");

                                                            CloseHandle(PipeHandles[Pipe]);

                                                }

                                                else

                                                            printf("ConnectNamedPipe() for pipe %d is OK!\n", i);

                                    }

 

                                    DataRead[Pipe] = FALSE;

                        }

                        else

                        {

                                    // Check the state of the pipe. If DataRead equals

                                    // FALSE, post a read on the pipe for incoming data.

                                    // If DataRead equals TRUE, then prepare to echo data back to the client.

                                    if (DataRead[Pipe] == FALSE)

                                    {

                                                // Prepare to read data from a client by posting a ReadFile operation

                                                ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                                                Ovlap[Pipe].hEvent = Event[Pipe];

                                                if (ReadFile(PipeHandles[Pipe], Buffer[Pipe],  BUFFER_SIZE, NULL, &Ovlap[Pipe]) == 0)

                                                {

                                                            if (GetLastError() != ERROR_IO_PENDING)

                                                            {

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

                                                            }

                                                }

                                                else

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

 

                                                DataRead[Pipe] = TRUE;

                                    }

                                    else

                                    {

                                                // Write received data back to the client by posting a WriteFile operation.

                                                printf("Received %d bytes, echo bytes back\n",   BytesTransferred);

 

                                                ZeroMemory(&Ovlap[Pipe], sizeof(OVERLAPPED));

                                                Ovlap[Pipe].hEvent = Event[Pipe];

 

                                                if (WriteFile(PipeHandles[Pipe], Buffer[Pipe],  BytesTransferred, NULL, &Ovlap[Pipe]) == 0)

                                                {

                                                            if (GetLastError() != ERROR_IO_PENDING)

                                                            {

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

                                                            }

                                                }

                                                else

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

 

                                                DataRead[Pipe] = FALSE;

                                    }

                        }

            }

}

 

Build and run the project.

 

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

Winsock: The Name Pipe Overlapped Server Program Example sample console output

 

Multithreaded Pipe Server Example

 

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

 

Winsock: The Multithreaded Pipe Server Program Example

 

Add the following source code.

 

#include <windows.h>

#include <stdio.h>

#include <tchar.h>

#include <strsafe.h>

 

#define BUFSIZE 4096

 

DWORD WINAPI InstanceThread(LPVOID);

VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

 

int main(int argc, char **argv)

{

   BOOL fConnected;

   DWORD dwThreadId;

   HANDLE hPipe, hThread;

   LPTSTR lpszPipename = L"\\\\.\\pipe\\jim";

 

   // The main loop creates an instance of the named pipe and

   // then waits for a client to connect to it. When the client

   // connects, a thread is created to handle communications

   // with that client, and this loop is free to wait for the next client connect request

   printf("Pipe Server: Awaiting initial client connection on %S\n", lpszPipename);

 

   for (;;)

   {

      hPipe = CreateNamedPipe(

          lpszPipename,                                    // pipe name

          PIPE_ACCESS_DUPLEX,              // read/write access

          PIPE_TYPE_MESSAGE |                // message type pipe

          PIPE_READMODE_MESSAGE |   // message-read mode

          PIPE_WAIT,                                     // blocking mode

          PIPE_UNLIMITED_INSTANCES, // max. instances

          BUFSIZE,                                          // output buffer size

          BUFSIZE,                                          // input buffer size

          0,                                                        // client time-out

          NULL);                                               // default security attribute

 

      if (hPipe == INVALID_HANDLE_VALUE)

      {

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

          return -1;

      }

      else

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

 

      // Wait for the client to connect; if it succeeds,

      // the function returns a nonzero value. If the function

      // returns zero, GetLastError returns ERROR_PIPE_CONNECTED

      fConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

 

      if (fConnected)

      {

         printf("Client connected, creating a processing thread...\n");

 

         // Create a thread for this client

         hThread = CreateThread(

            NULL,                          // no security attribute

            0,                                 // default stack size

            InstanceThread,         // thread proc

            (LPVOID) hPipe,       // thread parameter

            0,                                 // not suspended

            &dwThreadId);           // returns thread ID

 

         if (hThread == NULL)

         {

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

           return -1;

         }

         else

         {

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

                CloseHandle(hThread);

         }

     }

     else

        // The client could not connect, so close the pipe

        CloseHandle(hPipe);

   }

   return 0;

}

 

DWORD WINAPI InstanceThread(LPVOID lpvParam)

// This routine is a thread processing function to read from and reply to a client

// via the open pipe connection passed from the main loop. Note this allows

// the main loop to continue executing, potentially creating more threads of

// of this procedure to run concurrently, depending on the number of incoming client connections.

{

   HANDLE hHeap     = GetProcessHeap();

   CHAR* pchRequest = (CHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(CHAR));

   CHAR* pchReply   = (CHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(CHAR));

 

   DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;

   BOOL fSuccess = FALSE;

   HANDLE hPipe  = NULL;

 

   // Do some extra error checking in a compound statement, this could be

   // made more specific for different recovery routines if more robust

   // recovery is needed. For this example we simply quit

   if (lpvParam == NULL || pchRequest == NULL || pchReply == NULL)

   {

       printf( "\nERROR - Pipe Server Failure: InstanceThread() has an unexpected NULL value.\n");

       return 0;

   }

 

   // The thread's parameter is a handle to a pipe object instance

   hPipe = (HANDLE) lpvParam;

   // Loop until done reading

   while (1)

   {

         // Read client requests from the pipe

         fSuccess = ReadFile(

         hPipe,                                        // handle to pipe

         pchRequest,                             // buffer to receive data

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

         &cbBytesRead,                       // number of bytes read

         NULL);                                      // not overlapped I/O

 

      if (! fSuccess || cbBytesRead == 0)

         break;

      GetAnswerToRequest((LPTSTR)pchRequest, (LPTSTR)pchReply, &cbReplyBytes);

 

      // Write the reply to the pipe

      fSuccess = WriteFile(

         hPipe,                // handle to pipe

         pchReply,          // buffer to write from

         cbReplyBytes,  // number of bytes to write

         &cbWritten,       // number of bytes written

         NULL);               // not overlapped I/O

 

         if (! fSuccess || cbReplyBytes != cbWritten)

                break;

   }

 

   // Flush the pipe to allow the client to read the pipe's contents

   // before disconnecting. Then disconnect the pipe, and close the

   // handle to this pipe instance  

   FlushFileBuffers(hPipe);

   DisconnectNamedPipe(hPipe);

   CloseHandle(hPipe);

   HeapFree(hHeap, 0, pchRequest);

   HeapFree(hHeap, 0, pchReply);

   return 1;

}

 

VOID GetAnswerToRequest(LPTSTR pchRequest, LPTSTR pchReply, LPDWORD pchBytes)

// This routine is a simple function to print the client request to the console

// and populate the reply buffer with a default data string

{

    printf("Client Request String:\"%S\"\n", pchRequest);

    StringCchCopy(pchReply, BUFSIZE, L"\"Default answer from server\"");

    *pchBytes = (lstrlen(pchReply)+1)*sizeof(CHAR);

}

 

Build and run the project.

 

Winsock: The Multithreaded Pipe Server Program Example sample console output

 

Let test this project with the Name Pipe Client Example 2. Firstly, we run the server example.

 

Winsock: The Multithreaded Pipe Server Program Example testing the client with a server

 

Then we run the client 2 example. Take note that the received string was truncated.

 

Winsock: The Multithreaded Pipe Server Program Example, running the client sample output

 

The server sample output is shown below when communication was completed.

 

Winsock: The Multithreaded Pipe Server Program Example, the server sample output when communication was completed

 

 

 


< Name Pipes APIs & Client Program Example | Name Pipes Main | Overlapped I/O Server & Client Examples >