您的位置:首页 > 编程语言

IO完成端口入门级详细注释代码

2011-09-25 19:48 399 查看
#include "StdAfx.h"
#include "MyServer.h"
#include <WinSock2.h>

#pragma comment(lib, "Ws2_32.lib")//windows socket库
typedef struct __ARG
{
HANDLE hComplete;
SOCKET server;
}__ARG;

typedef struct CompleteKey
{
SOCKET socket;
}CompleteKey;

//overlap一定要放在第一位置
typedef struct
{
OVERLAPPED      overlap;       //重叠io必须的结构体
WSABUF          buf;         //系统缓冲区指针
char            data[1024];//数据缓存区
DWORD           NumberOfBytesRecvd;//发送或者接收的数据字节数
DWORD           Flags;
int OperationType;//操作类型
}IO_DATA;    //定义一个结构体保存IO数据

void initIoData(IO_DATA* ioData)//初始化io数据包
{
memset(ioData,0,sizeof(IO_DATA));
ioData->buf.buf=ioData->data;
ioData->buf.len=100;
ioData->Flags=0;

ioData->NumberOfBytesRecvd=100;
}

//弹出对话框
void myBox(char* format,...)
{
char buf[100]={0};
va_list ap;
va_start(ap, format);
sprintf_s(buf,format, ap);
va_end(ap);
MessageBoxA(0,buf,"",MB_OK);
}

//测试用函数
void test(SOCKET socket)
{
char buf[100]={0};
recv(socket,buf,100,0);
myBox(buf);
}

//创建一个IO完成端口
HANDLE CreateNewCompletionPort(DWORD dwNumberOfConcurrentThreads)
{
return( CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, dwNumberOfConcurrentThreads));
}

//将设备与完成端口管理起来
BOOL AssociateDeviceWithCompletionPort(HANDLE hCompletionPort, HANDLE hDevice,  DWORD dwCompletionKey)
{
HANDLE h = CreateIoCompletionPort(hDevice,   hCompletionPort, dwCompletionKey,   0);
return(h == hCompletionPort);
}

//初始化winsock环境
void initSocket()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);

err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
printf("WSAStartup failed with error: %d\n", err);
return ;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return ;
}
}

MyServer::MyServer(void)
{
//跟客户端端一样 初始化windows socket环境
initSocket();

//创建socket句柄
socksrv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(socksrv==INVALID_SOCKET)
{
myBox("create socket server error!");
}

//地址设定
addrsrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addrsrv.sin_family = AF_INET;
//端口设定
addrsrv.sin_port = htons(9999);

//绑定地址和端口
bind(socksrv,(sockaddr*)&addrsrv,sizeof(sockaddr));

//监听客户端请求
listen(socksrv,5);
}

MyServer::~MyServer(void)
{

}

//服务器工作线程
DWORD WINAPI ServerWorkerThread(LPVOID arg)
{
//	myBox("working\n");
IO_DATA *data=0;
CompleteKey *key=0;
DWORD recved;

initSocket();
while(1)
{
//异步接收的时候,传的是结构体中overlap的地址,这个地址和io_data结构体的地址是一致的 正是利用了这点,才巧妙的实现了异步获取数据
//data返回的指针即为异步接收的时候传入的指针
//key返回的指针即为绑定设备时候传入的指针
GetQueuedCompletionStatus((HANDLE)arg,&recved,(LPDWORD)&key,(LPOVERLAPPED*)&data,WSA_INFINITE);

//接收数据为0 说明客户端关闭连接
if(recved==0)
{
closesocket(key->socket);
delete key;
GlobalFree(data);
continue;
}

data->data[data->NumberOfBytesRecvd]=0;

//讲数据不改动的发送给客户端
send(key->socket,data->data,data->NumberOfBytesRecvd,0);

initIoData(data);//初始化IO数据包

//处理完数据后再次触发一次异步接收
WSARecv(key->socket,&data->buf,1, &data->NumberOfBytesRecvd, &data->Flags,&data->overlap, NULL) ;
}
return 0;
}

//接收请求的线程
DWORD WINAPI MainThread(LPVOID arg)
{
__ARG *args=(__ARG*)arg;
SOCKET client;
initSocket();
while(1)
{
SOCKADDR_IN saRemote;
int nRemoteLen = sizeof(saRemote);

//接受一个连接请求
client= accept(args->server, (sockaddr*)&saRemote, &nRemoteLen);

if(client==SOCKET_ERROR)
{
myBox("client error!\n");
break;
}

//创建一个完成键
CompleteKey* key=new CompleteKey();
key->socket=client;

//把接收到的客户socket当成设备管理到完成端口
//key   标识这个设备的一些数据
if(AssociateDeviceWithCompletionPort(args->hComplete,(HANDLE)client,(DWORD)key)==FALSE)//关联设备
myBox("设备关联失败!");

IO_DATA *ioData = (IO_DATA *)GlobalAlloc(GPTR,sizeof(IO_DATA));//初始化一个io完成数据

initIoData(ioData);

//test(client);

//触发一个异步接收请求  该函数调用后立马返回
int ret=WSARecv(client,&ioData->buf,1, &ioData->NumberOfBytesRecvd, &ioData->Flags,&ioData->overlap, NULL) ;

//注意多判断一个错误码~  如果错误码是WSA_IO_PENDING 其实也是正常状态,因为
//该错误码表明异步操作成功,等待指示。(客户端调用connect后被阻塞了,就会出现这种情况)
if(ret==SOCKET_ERROR && WSAGetLastError()!=WSA_IO_PENDING)
{
myBox("wsaRecv error :%d \n",WSAGetLastError());
}
}
return 0;
}

void MyServer::begin()
{
int threads=2;
HANDLE hCompletion = CreateNewCompletionPort(threads);//创建两个工作线程
if(hCompletion==0)
{
myBox("端口创建失败!");
return;
}
int i=0;
DWORD threadId;
for(i=0;i<threads;i++)
{
CreateThread(0,0,ServerWorkerThread,hCompletion,0,&threadId);
}
__ARG *arg=new __ARG();
arg->hComplete=hCompletion;
arg->server=socksrv;

CreateThread(0,0,MainThread,arg,0,&threadId);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: