< Overlapped I/O Server & Client Examples | Name Pipes Main | End! >
What do we have in this chapter 15 part 6?
|
Named Pipe Server Using Completion Routines Example
Create a new empty Win32 console mode application and add the project/solution name.
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>
// http://msdn.microsoft.com/en-us/library/ms647466.aspx
#include <strsafe.h>
// Constants
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
// Struct typedef
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
} PIPEINST, *LPPIPEINST;
// Prototypes
VOID DisconnectAndClose(LPPIPEINST);
BOOL CreateAndConnectInstance(LPOVERLAPPED);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
// Global var
HANDLE hPipe;
int _tmain(int argc, TCHAR **argv)
{
HANDLE hConnectEvent;
OVERLAPPED oConnect;
LPPIPEINST lpPipeInst;
DWORD dwWait, cbRet;
BOOL fSuccess, fPendingIO;
// Create one event object for the connect operation
hConnectEvent = CreateEvent(
NULL, // default security attribute
TRUE, // manual reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hConnectEvent == NULL)
{
printf("CreateEvent() failed with error code %d\n", GetLastError());
return 0;
}
else
printf("CreateEvent() is OK!\n");
oConnect.hEvent = hConnectEvent;
// Call a subroutine to create one instance, and wait for the client to connect
fPendingIO = CreateAndConnectInstance(&oConnect);
while (1)
{
// Wait for a client to connect, or for a read or write
// operation to be completed, which causes a completion
// routine to be queued for execution
dwWait = WaitForSingleObjectEx(
hConnectEvent, // event object to wait for
INFINITE, // waits indefinitely
TRUE); // alertable wait enabled
switch (dwWait)
{
// The wait conditions are satisfied by a completed connect operation
case 0:
// If an operation is pending, get the result of the connect operation
if (fPendingIO)
{
fSuccess = GetOverlappedResult(
hPipe, // pipe handle
&oConnect, // OVERLAPPED structure
&cbRet, // bytes transferred
FALSE); // does not wait
if (!fSuccess)
{
printf("ConnectNamedPipe() failed with error code %d\n", GetLastError());
return 0;
}
else
printf("ConnectNamedPipe() is OK!\n");
}
// Allocate storage for this instance
lpPipeInst = (LPPIPEINST) GlobalAlloc(GPTR, sizeof(PIPEINST));
if (lpPipeInst == NULL)
{
printf("GlobalAlloc() for buffer failed with error code %d\n", GetLastError());
return 0;
}
else
printf("GlobalAlloc() for buffer is OK!\n");
lpPipeInst->hPipeInst = hPipe;
// Start the read operation for this client
// Note that this same routine is later used as a
// completion routine after a write operation
lpPipeInst->cbToWrite = 0;
CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst);
// Create new pipe instance for the next client
fPendingIO = CreateAndConnectInstance(&oConnect);
break;
// The wait is satisfied by a completed read or write
// operation. This allows the system to execute the completion routine
case WAIT_IO_COMPLETION:
break;
// An error occurred in the wait function
default:
{
printf("WaitForSingleObjectEx() failed with error code %d\n", GetLastError());
return 0;
}
}
}
return 0;
}
// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED)
// This routine is called as a completion routine after writing to
// the pipe, or when a new client has connected to a pipe instance, it starts another read operation
VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fRead = FALSE;
// lpOverlap points to storage for this instance
lpPipeInst = (LPPIPEINST) lpOverLap;
// The write operation has finished, so read the next request (if there is no error)
if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))
fRead = ReadFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chRequest,
BUFSIZE*sizeof(TCHAR),
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine);
// Disconnect if an error occurred
if (! fRead)
DisconnectAndClose(lpPipeInst);
}
// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED)
// This routine is called as an I/O completion routine after reading
// a request from the client. It gets data and writes it to the pipe
VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap)
{
LPPIPEINST lpPipeInst;
BOOL fWrite = FALSE;
// lpOverlap points to storage for this instance
lpPipeInst = (LPPIPEINST) lpOverLap;
// The read operation has finished, so write a response (if no error occurred)
if ((dwErr == 0) && (cbBytesRead != 0))
{
GetAnswerToRequest(lpPipeInst);
fWrite = WriteFileEx(
lpPipeInst->hPipeInst,
lpPipeInst->chReply,
lpPipeInst->cbToWrite,
(LPOVERLAPPED) lpPipeInst,
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine);
}
// Disconnect if an error occurred
if (! fWrite)
DisconnectAndClose(lpPipeInst);
}
// DisconnectAndClose(LPPIPEINST)
// This routine is called when an error occurs or the client closes its handle to the pipe
VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
{
// Disconnect the pipe instance
if (! DisconnectNamedPipe(lpPipeInst->hPipeInst))
{
printf("DisconnectNamedPipe() failed with error code %d.\n", GetLastError());
}
else
printf("DisconnectNamedPipe() is fine!\n");
// Close the handle to the pipe instance
printf("Closing the handle...\n");
CloseHandle(lpPipeInst->hPipeInst);
// Release the storage for the pipe instance
printf("De-allocate the buffer...\n");
if (lpPipeInst != NULL)
GlobalFree(lpPipeInst);
}
// CreateAndConnectInstance(LPOVERLAPPED)
// This function creates a pipe instance and connects to the client
// It returns TRUE if the connect operation is pending, and FALSE if
// the connection has been completed
BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
{
LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\pipebodo");
hPipe = 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
PIPE_UNLIMITED_INSTANCES, // unlimited instances
BUFSIZE*sizeof(TCHAR), // output buffer size
BUFSIZE*sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
if (hPipe == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe() failed with error code %d.\n", GetLastError());
return 0;
}
else
printf("CreateNamedPipe() is OK!\n");
// Call a subroutine to connect to the new client
return ConnectToNewClient(hPipe, lpoOverlap);
}
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() should be 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.
--------------------------------------------------------------
Let test this server program with the previous client program example. Firstly, run the server program.
Then run the client program example.
The previous server program sample output is shown below when the client communication was completed.
< Overlapped I/O Server & Client Examples | Name Pipes Main | End! >