Home   Index   About
Ultimate Pack


Custom Search
Server Using Overlapped Input and Output

This example is a single-threaded server process that uses overlapped operations to service simultaneous connections to multiple client processes. The server process creates a fixed number of pipe instances, each of which can be connected to a separate client process. When a client process has finished using its pipe instance, the server disconnects from the client and reuses the pipe instance to connect to a new client.

Associated with each pipe instance is an OVERLAPPED structure containing an event object. This structure is specified as a parameter in each ReadFile, WriteFile, and ConnectNamedPipe operation on the pipe instance. Although the example shows simultaneous operations on different pipe instances, it avoids simultaneous operations on a single pipe instance. Because the same event object is used for read, write, and connect operations for each instance, there is no way to know which operation's completion caused the event to be set to the signaled state for simultaneous operations using the same pipe instance.

The event handles for each pipe instance are also stored in an array used by the WaitForMultipleObjects function. This function waits for one of the events to be signaled, and its return value is the array index of the event that satisfied the wait. The example uses this index to retrieve a structure containing information for the pipe instance. The server uses the fPendingIO member of the structure to keep track of whether the most recent I/O operation on the instance was pending, necessitating a call to the GetOverlappedResult function. It uses the dwState member of the structure to determine the next operation that must be performed for the instance.

Overlapped ReadFile, WriteFile, and ConnectNamedPipe operations may have finished when the function returns, or they may still be pending when the function returns. If the operation is pending, the event object in the specified OVERLAPPED structure is set to the nonsignaled state before the function returns. When the pending operation has finished, the system sets the state of the event object to signaled. The state of the event object is not changed if the operation finishes before the function returns.

Because the example uses manual reset event objects, the state of the event objects is not changed to nonsignaled by the WaitForMultipleObjects function. This is important, because the example relies on the event objects remaining in the signaled state except when there is a pending operation.

If the operation is already finished when ReadFile, WriteFile, or ConnectNamedPipe returns, the function's return value indicates the result. For read and write operations, the number of bytes transferred is also returned. If the operation is still pending, the ReadFile, WriteFile, or ConnectNamedPipe function returns FALSE and the GetLastError function returns ERROR_IO_PENDING. In this case, the results are retrieved using the GetOverlappedResult function after the operation has finished. GetOverlappedResult returns only the results of operations that were pending, and does not report the results of operations that were completed before the overlapped ReadFile, WriteFile, or ConnectNamedPipe function returned.

Before disconnecting from a client, the multithreaded server example in the previous section used FlushFileBuffers to ensure that the client had read everything written to the pipe. This would defeat the purpose of overlapped I/O, because the flush operation would block the execution of the server thread while it waits for the client to empty the pipe. Consequently, it is necessary to wait for a signal from the client that it has finished before disconnecting. In this example, the signal is the error generated by trying to read from the pipe after the client process closes its handle.

#include <windows.h>

#define CONNECTING_STATE 0

#define READING_STATE 1

#define WRITING_STATE 2

#define INSTANCES 4

typedef struct

{

OVERLAPPED oOverlap;

HANDLE hPipeInst;

CHAR chBuf[BUFSIZE];

DWORD cbToWrite;

DWORD dwState;

BOOL fPendingIO;

} PIPEINST, *LPPIPEINST;

VOID DisconnectAndReconnect(DWORD);

BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);

VOID GetDataToWriteToClient(LPPIPEINST);

PIPEINST Pipe[INSTANCES];

HANDLE hEvents[INSTANCES];

DWORD main(VOID)

{

DWORD i, dwWait, cbBytes, dwErr;

BOOL fSuccess;

LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe";

// 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, // no security attribute

TRUE, // manual-reset event

TRUE, // initial state = signaled

NULL); // unnamed event object

if (hEvents[i] == NULL)

MyErrExit("CreateEvent");

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, // output buffer size

BUFSIZE, // input buffer size

PIPE_TIMEOUT, // client time-out

NULL); // no security attributes

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

MyErrExit("CreatePipe");

// 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))

MyErrExit("index out of range");

// 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

&cbBytes, // bytes transferred

FALSE); // do not wait

switch (Pipe[i].dwState)

{

// Pending connect operation

case CONNECTING_STATE:

if (! fSuccess)

MyErrExit("ConnectNamedPipe");

Pipe[i].dwState = READING_STATE;

break;

// Pending read operation

case READING_STATE:

if (! fSuccess || cbBytes == 0)

{

DisconnectAndReconnect(i);

continue;

}

Pipe[i].dwState = WRITING_STATE;

break;

// Pending write operation

case WRITING_STATE:

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

{

DisconnectAndReconnect(i);

continue;

}

Pipe[i].dwState = READING_STATE;

break;

default:

MyErrExit("invalid pipe state");

}

}

// 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].chBuf,

BUFSIZE,

&cbBytes,

&Pipe[i].oOverlap);

// The read operation completed successfully.

if (fSuccess && cbBytes != 0)

{

Pipe[i].fPendingIO = FALSE;

Pipe[i].dwState = WRITING_STATE;

continue;

}

// The read operation is still pending

dwErr = GetLastError();

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

{

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:

GetDataToWriteToClient(&Pipe[i]);

fSuccess = WriteFile(

Pipe[i].hPipeInst,

Pipe[i].chBuf,

Pipe[i].cbToWrite,

&cbBytes,

&Pipe[i].oOverlap);

// The write operation completed successfully.

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

{

Pipe[i].fPendingIO = FALSE;

Pipe[i].dwState = READING_STATE;

continue;

}

// The write operation is still pending.

dwErr = GetLastError();

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

{

Pipe[i].fPendingIO = TRUE;

continue;

}

// An error occurred; disconnect from the client.

DisconnectAndReconnect(i);

break;

default:

MyErrExit("invalid pipe state");

}

}

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) )

MyErrExit("DisconnectNamedPipe");

// 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 FALSE.

if (fConnected)

MyErrExit("ConnectNamedPipe");

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:

MyErrExit("ConnectNamedPipe");

}

return fPendingIO;

}


Last news from Greatis Software

Nostalgia .Net     Nostalgia .Net     .Net is powerful, but not all-powerful, so sometimes we need to use Win32 API for our .Net applications. It's simple enough with Platform Invoke if you have Win32 skill, but we do not always have time to dig the ancient documentation, declare the special types that are compatible with Win32, find the values of the Win32's constants and so on. Nostalgia .Net offers several simple-to-use classes, and components that will allow you to forget about the headache of Win32 and just use the power of Win32 in your application the same way as you use the native. Net classes.  More »

Recommended software for developers

Ultimate Pack for Delphi and C++ Builder     Ultimate Pack     Component pack for Delphi and C++ Builder that contains runtime form designer, runtime object inspector, print suite and much more for the very special price.  More »

Form Designer .Net     Form Designer .Net     Unique runtime form design solution that allows to edit any form in .Net WinForms application at runtime with full source codes for only 300 euro!  More »

Print Suite .Net     Print Suite .Net     Print Suite .Net is a set of components for easy printing texts, images and grids from your WinForms applications. Full C# source codes are available  More »

Gradient Controls .Net     Gradient Controls .Net     Gradient Controls .Net offers controls with gradient background feature. Labels, panels and so on... Full C# source codes are available  More »

iGrid     Greatis iGrid     iGrid plots drawing grid right over your desktop, so you can use it everywhere, with any drawing application without any special plugins for different graphic editors.  More »


All the contacts and projects

Dmitry Vasiliev (just.dmitry)

Related Links

Software for Visual Studio .NET developers
Software for Delphi and C++ Builder developers
Software for Visual Basic 6 developers
Delphi Tips&Tricks
MegaDetailed.NET

More Online Helps

Win32 Programmer's Reference
Win32 Multimedia Programmer's Reference
OLE Programmer's Reference
Microsoft Windows Pen API Programmer's Reference
Microsoft Windows Sockets 2 Reference
Microsoft Windows Telephony API (TAPI) Programmer's Reference
Unix Manual Pages

Free Tech Secrets ;) Copyright © 2008-2012 Free Tech Secrets ;) greatis just4fun network just4fun