【转】完成端口例子
本文转载来自CSDN博客
http://blog.csdn.net/nicholasmaxwell/archive/2006/05/18/744467.aspxhttp://blog.csdn.net/nicholasmaxwell/archive/2006/05/18/744464.aspx
另外一篇值得参考的《完成端口I/O模型编写心得!》http://blog.csdn.net/jasonm2008/archive/2009/08/14/4441514.aspx#
#include
"
stdafx.h
"
#include < iostream.h >
#include
#include
#include
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct
{
OVERLAPPED OVerlapped;
WSABUF DATABuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSend,BytesRecv;
}PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET Socket;
}PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID);
int main( int argc, char * argv[])
{
SOCKADDR_IN InternetAddr;
SOCKET Listen,Accept;
HANDLE CompetionPort;
SYSTEM_INFO SystenInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIOData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsadata;
DWORD Ret;
if (Ret = WSAStartup( 0x2020 , & wsadata) != 0 )
{
printf( " WSAStartup failed with error %d\n " ,Ret);
return 0 ;
}
// 打开一个空的完成端口
if ((CompetionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 , 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error %d\n " ,GetLastError());
return 0 ;
}
GetSystemInfo( & SystenInfo);
// 开启cpu个数的2倍个的线程
for (i = 0 ; i < SystenInfo.dwNumberOfProcessors * 2 ; i ++ )
{
HANDLE ThreadHandle;
// 创建服务器工作线程,并且向线程传送完成端口
if ((ThreadHandle = CreateThread(NULL, 0 ,ServerWorkerThread,CompetionPort, 0 , & ThreadID)) == NULL)
{
printf( " CreateThread failed with error %d\n " ,GetLastError());
return 0 ;
}
CloseHandle(ThreadHandle);
}
// 打开一个服务器socket
if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0 , NULL, 0 , WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf( " WSASocket() failed with error %d\n " , WSAGetLastError());
return 0 ;
}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(Listen,(LPSOCKADDR) & InternetAddr, sizeof (InternetAddr)) == SOCKET_ERROR)
{
printf( " bind failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
if (listen(Listen, 5 ) == SOCKET_ERROR)
{
printf( " listen failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
// 接收连接并且分发给完成端口
while (TRUE)
{
if ((Accept = WSAAccept(Listen,NULL,NULL,NULL, 0 )) == SOCKET_ERROR)
{
printf( " WSAAccept failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
// 创建与套接字相关的套接字信息结构
if ((PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof (PER_HANDLE_DATA))) == NULL)
{
printf( " GlobalAlloc failed with error %d\n " ,GetLastError());
return 0 ;
}
// Associate the accepted socket with the original completion port.
printf( " Socket number %d connected\n " ,Accept);
PerHandleData -> Socket = Accept; // 结构中存入接收的套接字
// 与我们的创建的那个完成端口关联起来,将关键项也与指定的一个完成端口关联
if ((CreateIoCompletionPort((HANDLE)Accept,CompetionPort,(DWORD)PerHandleData, 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error%d\n " ,GetLastError());
return 0 ;
}
// 创建同下面的WSARecv调用相关的IO套接字信息结构体
if ((PerIOData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof (PER_IO_OPERATION_DATA))) = NULL)
{
printf( " GlobalAloc failed with error %d\n " ,GetLastError());
return 0 ;
}
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> BytesRecv = 0 ;
PerIOData -> BytesSend = 0 ;
PerIOData -> DATABuf.len = DATA_BUFSIZE;
PerIOData -> DATABuf.buf = PerIOData -> Buffer;
Flags = 0 ;
if (WSARecv(Accept, & (PerIOData -> DATABuf), 1 , & RecvBytes, & Flags, & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSARecv() failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
return 0 ;
}
#include < iostream.h >
#include
#include
#include
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct
{
OVERLAPPED OVerlapped;
WSABUF DATABuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSend,BytesRecv;
}PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET Socket;
}PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID);
int main( int argc, char * argv[])
{
SOCKADDR_IN InternetAddr;
SOCKET Listen,Accept;
HANDLE CompetionPort;
SYSTEM_INFO SystenInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIOData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsadata;
DWORD Ret;
if (Ret = WSAStartup( 0x2020 , & wsadata) != 0 )
{
printf( " WSAStartup failed with error %d\n " ,Ret);
return 0 ;
}
// 打开一个空的完成端口
if ((CompetionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL, 0 , 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error %d\n " ,GetLastError());
return 0 ;
}
GetSystemInfo( & SystenInfo);
// 开启cpu个数的2倍个的线程
for (i = 0 ; i < SystenInfo.dwNumberOfProcessors * 2 ; i ++ )
{
HANDLE ThreadHandle;
// 创建服务器工作线程,并且向线程传送完成端口
if ((ThreadHandle = CreateThread(NULL, 0 ,ServerWorkerThread,CompetionPort, 0 , & ThreadID)) == NULL)
{
printf( " CreateThread failed with error %d\n " ,GetLastError());
return 0 ;
}
CloseHandle(ThreadHandle);
}
// 打开一个服务器socket
if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0 , NULL, 0 , WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf( " WSASocket() failed with error %d\n " , WSAGetLastError());
return 0 ;
}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(Listen,(LPSOCKADDR) & InternetAddr, sizeof (InternetAddr)) == SOCKET_ERROR)
{
printf( " bind failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
if (listen(Listen, 5 ) == SOCKET_ERROR)
{
printf( " listen failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
// 接收连接并且分发给完成端口
while (TRUE)
{
if ((Accept = WSAAccept(Listen,NULL,NULL,NULL, 0 )) == SOCKET_ERROR)
{
printf( " WSAAccept failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
// 创建与套接字相关的套接字信息结构
if ((PerHandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof (PER_HANDLE_DATA))) == NULL)
{
printf( " GlobalAlloc failed with error %d\n " ,GetLastError());
return 0 ;
}
// Associate the accepted socket with the original completion port.
printf( " Socket number %d connected\n " ,Accept);
PerHandleData -> Socket = Accept; // 结构中存入接收的套接字
// 与我们的创建的那个完成端口关联起来,将关键项也与指定的一个完成端口关联
if ((CreateIoCompletionPort((HANDLE)Accept,CompetionPort,(DWORD)PerHandleData, 0 )) == NULL)
{
printf( " CreateIoCompletionPort failed with error%d\n " ,GetLastError());
return 0 ;
}
// 创建同下面的WSARecv调用相关的IO套接字信息结构体
if ((PerIOData = (LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR, sizeof (PER_IO_OPERATION_DATA))) = NULL)
{
printf( " GlobalAloc failed with error %d\n " ,GetLastError());
return 0 ;
}
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> BytesRecv = 0 ;
PerIOData -> BytesSend = 0 ;
PerIOData -> DATABuf.len = DATA_BUFSIZE;
PerIOData -> DATABuf.buf = PerIOData -> Buffer;
Flags = 0 ;
if (WSARecv(Accept, & (PerIOData -> DATABuf), 1 , & RecvBytes, & Flags, & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSARecv() failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
return 0 ;
}
工作者线程
//
工作线程
DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID)
{
HANDLE ComplectionPort = (HANDLE) ComlpetionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIOData;
DWORD SendBytes,RecvBytes;
DWORD Flags;
while (TRUE)
{
if (GetQueuedCompletionStatus(ComplectionPort, & BytesTransferred,(LPDWORD) & PerHandleData,(LPOVERLAPPED * ) & PerIOData,INFINITE) == 0 )
{
printf( " GetQueuedCompletionStatus failed with error%d\n " ,GetLastError());
return 0 ;
}
// 首先检查套接字上是否发生错误,如果发生了则关闭套接字并且清除同套节字相关的SOCKET_INFORATION 结构体
if (BytesTransferred == 0 )
{
printf( " Closing Socket %d\n " ,PerHandleData -> Socket);
if (closesocket(PerHandleData -> Socket) == SOCKET_ERROR)
{
printf( " closesocket failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
GlobalFree(PerHandleData);
GlobalFree(PerIOData);
continue ;
}
// 检查BytesRecv域是否等于0,如果是,说明WSARecv调用刚刚完成,可以用从己完成的WSARecv调用返回的BytesTransferred值更新BytesRecv域
if (PerIOData -> BytesRecv == 0 )
{
PerIOData -> BytesRecv = BytesTransferred;
PerIOData -> BytesSend = 0 ;
}
else
{
PerIOData -> BytesRecv += BytesTransferred;
}
//
if (PerIOData -> BytesRecv > PerIOData -> BytesSend)
{
// 发布另一个WSASend()请求,因为WSASendi 不能确保发送了请的所有字节,继续WSASend调用直至发送完所有收到的字节
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> DATABuf.buf = PerIOData -> Buffer + PerIOData -> BytesSend;
PerIOData -> DATABuf.len = PerIOData -> BytesRecv - PerIOData -> BytesSend;
if (WSASend(PerHandleData -> Socket, & (PerIOData -> DATABuf), 1 , & SendBytes, 0 , & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR )
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSASend() fialed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
else
{
PerIOData -> BytesRecv = 0 ;
// Now that is no more bytes to send post another WSARecv() request
// 现在己经发送完成
Flags = 0 ;
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> DATABuf.buf = PerIOData -> Buffer;
PerIOData -> DATABuf.len = DATA_BUFSIZE;
if (WSARecv(PerHandleData -> Socket, & (PerIOData -> DATABuf), 1 , & RecvBytes, & Flags, & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSARecv() failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
}
}
DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID)
{
HANDLE ComplectionPort = (HANDLE) ComlpetionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIOData;
DWORD SendBytes,RecvBytes;
DWORD Flags;
while (TRUE)
{
if (GetQueuedCompletionStatus(ComplectionPort, & BytesTransferred,(LPDWORD) & PerHandleData,(LPOVERLAPPED * ) & PerIOData,INFINITE) == 0 )
{
printf( " GetQueuedCompletionStatus failed with error%d\n " ,GetLastError());
return 0 ;
}
// 首先检查套接字上是否发生错误,如果发生了则关闭套接字并且清除同套节字相关的SOCKET_INFORATION 结构体
if (BytesTransferred == 0 )
{
printf( " Closing Socket %d\n " ,PerHandleData -> Socket);
if (closesocket(PerHandleData -> Socket) == SOCKET_ERROR)
{
printf( " closesocket failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
GlobalFree(PerHandleData);
GlobalFree(PerIOData);
continue ;
}
// 检查BytesRecv域是否等于0,如果是,说明WSARecv调用刚刚完成,可以用从己完成的WSARecv调用返回的BytesTransferred值更新BytesRecv域
if (PerIOData -> BytesRecv == 0 )
{
PerIOData -> BytesRecv = BytesTransferred;
PerIOData -> BytesSend = 0 ;
}
else
{
PerIOData -> BytesRecv += BytesTransferred;
}
//
if (PerIOData -> BytesRecv > PerIOData -> BytesSend)
{
// 发布另一个WSASend()请求,因为WSASendi 不能确保发送了请的所有字节,继续WSASend调用直至发送完所有收到的字节
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> DATABuf.buf = PerIOData -> Buffer + PerIOData -> BytesSend;
PerIOData -> DATABuf.len = PerIOData -> BytesRecv - PerIOData -> BytesSend;
if (WSASend(PerHandleData -> Socket, & (PerIOData -> DATABuf), 1 , & SendBytes, 0 , & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR )
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSASend() fialed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
else
{
PerIOData -> BytesRecv = 0 ;
// Now that is no more bytes to send post another WSARecv() request
// 现在己经发送完成
Flags = 0 ;
ZeroMemory( & (PerIOData -> OVerlapped), sizeof (OVERLAPPED));
PerIOData -> DATABuf.buf = PerIOData -> Buffer;
PerIOData -> DATABuf.len = DATA_BUFSIZE;
if (WSARecv(PerHandleData -> Socket, & (PerIOData -> DATABuf), 1 , & RecvBytes, & Flags, & (PerIOData -> OVerlapped),NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf( " WSARecv() failed with error %d\n " ,WSAGetLastError());
return 0 ;
}
}
}
}
}