网络编程(三)
多线程,重叠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;
}
}
}
}