< Multithreaded & Overlapped Server Examples | Name Pipes Main | Completion Routines Server Example >
What do we have in this chapter 15 part 5?
|
Another Named Pipe Server Using Overlapped I/O
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> |
// 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
Connected = 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.
----------------------------------------------------
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>
#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.
Let test this client with the previous server program. Firstly we run the server program.
Next we run the client program twice.
The previous server sample output is shown below.
< Multithreaded & Overlapped Server Examples | Name Pipes Main | Completion Routines Server Example >