多线程,重叠I/O,异步读写 命名通道服务器源码

/*
* 文件名称:NamedPipeServer.cpp
*
* 文件作用:测试建立多线程复杂命名管道服务器
*
* 完成日期:2007.04.03
*/

#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];

// 对每一个通道句柄实例来说,当它进行在读写操作时,代码必须维持通道的当前状态
// 这个可以用DataRead这个变量数组来实现.当我们确定了管道的当前状态,代码能够
// 确定下一个I/O操作是什么
BOOL DataRead[ NUM_PIPES ];

DWORD Ret;
DWORD Pipe;

for( i = 0; i < NUM_PIPES; i++ )
{
    // 为每个命名管道实例创建一个线程,并调用其回调函数
    if ((PipeHandles[i] = CreateNamedPipe("\\\\.\\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;
    }

    // 为每个命名通道创建一个事件句柄
    if ((Event[i] = CreateEvent(NULL, TRUE, FALSE, NULL)) 
     == NULL)
    {
     printf("CreateEvent for pipe %d failed with error %d\n",
      i, GetLastError());
     continue;
    }
  
    // 当确定命名通道在进行读写工作时候,为其维持一个状态
    DataRead[i] = FALSE;

    ZeroMemory(&Ovlap[i], sizeof(OVERLAPPED));
    Ovlap[i].hEvent = Event[i];

    // 监听客户端,使用异步操作,不需要僵直等待
    if ( ConnectNamedPipe(PipeHandles[i], &Ovlap[i]) == 0) 
    {
     if ( GetLastError() != ERROR_IO_PENDING )
     {
      printf("ConnectNamedPipe for pipe %d failed with",
          " error %d\n", i, GetLastError());
      CloseHandle(PipeHandles[i]);
      return;
     }
    }
}

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


// 持续处理客户端信息
while( 1 ) 
{
    if (( Ret = WaitForMultipleObjects(NUM_PIPES, Event, 
     FALSE, INFINITE)) == WAIT_FAILED )
    {
     printf("WaitForMultipleObjects failed with error %d\n",
      GetLastError());
     return;
    }

    Pipe = Ret - WAIT_OBJECT_0;

    ResetEvent(Event[Pipe]);

    // 检查重叠异步结果,如果失败,则和新的客户端重建链接
    // 不然,和客户端处理读写过程

    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;
     }

     if (ConnectNamedPipe(PipeHandles[Pipe],
      &Ovlap[Pipe]) == 0)
     {
      if (GetLastError() != ERROR_IO_PENDING)
      {
       // 命名通道出现严重错误,永久性关闭句柄
       printf("ConnectNamedPipe for pipe %d failed with"
        "error %d\n", i, GetLastError());
       CloseHandle(PipeHandles[Pipe]);
      }
     }

     DataRead[Pipe] = FALSE;
    } 
    else
    {
     // 检查通道状态,如果DataRead是FALSE,则对通道输入数据进行读操作
     // 若DataRead状态是TRUE,则准备对客户端进行信息反馈

     if (DataRead[Pipe] == FALSE)
     {

      // 准备从客户端进行数据的读取
      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());
       }
      }

      DataRead[Pipe] = TRUE;
     }
     else
     {
      // 对客户端进行反馈信息的写入操作
      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());
       }
      }

      DataRead[Pipe] = FALSE;
     }
    }
}  
}