【Windows网络编程】重叠IO网络模型

来源:互联网 发布:linux增加分辨率 编辑:程序博客网 时间:2024/03/29 23:19
//把数据从网卡复制到程序的buffer,但是也要时间。。重叠io就是解决这个问题#include <WinSock2.h>#include <stdio.h>#define  PORT 6000#define  MSGSIZE 1024#pragma  comment (lib,"Ws2_32.lib")BOOL WinSockInit(){WSADATA data = { 0 };if (WSAStartup(MAKEWORD(2, 2), &data))return FALSE;if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion != 2)){WSACleanup();return FALSE;}return TRUE;}//单io操作。。buf。。typedef struct{WSAOVERLAPPED overlap;     //第一个成员。重叠io,必须用OVERLAPPEDWSABUF buffer;//发送长度或者接收的时候允许的最大长度char szMessage[MSGSIZE];DWORD NumberOfBytesRecvd;   //保存接收到的字节数DWORD Flags;//保存操作类型。。收。。发。。}PER_IO_OPERATION_DATA,  *LPPER_IO_OPERATION_DATA;int g_iTotalConn = 0;SOCKET g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];LPPER_IO_OPERATION_DATA g_pPerIODataArr[MAXIMUM_WAIT_OBJECTS];DWORD WINAPI WorkerThread(LPWORD);void Cleanup(int);int main(){SOCKET sListen, sClient;SOCKADDR_IN local, client;DWORD dwThreadId;int iaddrSize = sizeof(SOCKADDR_IN);//初始化windowa socket库WinSockInit();//创建监听socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //默认设置WSA_FLAG_OVERLAPPED//绑定local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);local.sin_family = AF_INET;local.sin_port = htonl(PORT);bind(sListen, (struct sockaddr*)&local, sizeof(SOCKADDR_IN));//监听listen(sListen, 3);//创建工作者线程CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)WorkerThread, NULL, 0, &dwThreadId);while (TRUE){//接受连接sClient = accept(sListen, (struct sockaddr*)&client, &iaddrSize);printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));g_CliSocketArr[g_iTotalConn] = sClient;//分配一个单io操作 数据结构g_pPerIODataArr[g_iTotalConn] = (LPPER_IO_OPERATION_DATA)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PER_IO_OPERATION_DATA));g_pPerIODataArr[g_iTotalConn]->buffer.len = MSGSIZE;g_pPerIODataArr[g_iTotalConn]->buffer.buf = g_pPerIODataArr[g_iTotalConn]->szMessage;g_CliEventArr[g_iTotalConn] = g_pPerIODataArr[g_iTotalConn]->overlap.hEvent = WSACreateEvent();//g_pPerIODataArr[g_iTotalConn].Flags = 1;//开始一个异步操作-不会阻塞程序。。告诉小秘按结构体进行数据操作WSARecv(g_CliSocketArr[g_iTotalConn],&g_pPerIODataArr[g_iTotalConn]->buffer,1,&g_pPerIODataArr[g_iTotalConn]->NumberOfBytesRecvd,&g_pPerIODataArr[g_iTotalConn]->Flags, &g_pPerIODataArr[g_iTotalConn]->overlap,NULL);//WSARecv的参数都有一个Overlapped参数,我们可以假设是我们的WSARecv这样的操作绑定到这个重叠结构上//提交一个请求,而不是将操作立即完成,其他事情交给重叠结构去做,而其中重叠结构要与事件对象绑定在一起//这样我们调用完WSARecv以后就可以“坐享其成”,等重叠操作完成后,自然会有与之对应的的事件通知我们操作完成//然后我们就可以根据重叠操作的结果取得我们想要的数据了g_iTotalConn++;}closesocket(sListen);WSACleanup();return 0;}DWORD WINAPI WorkerThread(LPWORD lpParam){int ret, index;DWORD cbTransferred;while (TRUE){//判断出一个重叠IO调用是否完成ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);if (ret==WSA_WAIT_FAILED||ret==WSA_WAIT_TIMEOUT)continue;index = ret - WSA_WAIT_EVENT_0;WSAResetEvent(g_CliEventArr[index]);   //手动设置为未传信,WSAGetOverlappedResult(g_CliSocketArr[index],&g_pPerIODataArr[index]->overlap,&cbTransferred,TRUE,&g_pPerIODataArr[g_iTotalConn]->Flags); //判断该重叠调用成功还是失败if (cbTransferred == 0)Cleanup(index);  //客户端连接关闭else{//g_pPerIODataArr[index]->szMessage保存接收到的数据g_pPerIODataArr[index]->szMessage[cbTransferred] = '\0';send(g_CliSocketArr[index], g_pPerIODataArr[index]->szMessage,cbTransferred, 0);//进行另一个异步操作WSARecv(g_CliSocketArr[index],&g_pPerIODataArr[index]->buffer,1,&g_pPerIODataArr[index]->NumberOfBytesRecvd,&g_pPerIODataArr[index]->Flags,&g_pPerIODataArr[index]->overlap,NULL);}}return 0;}void Cleanup(int index){closesocket(g_CliSocketArr[index]);WSACloseEvent(g_CliEventArr[index]);HeapFree(GetProcessHeap(), 0, g_pPerIODataArr[index]);if (index < g_iTotalConn - 1){g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];g_pPerIODataArr[index] = g_pPerIODataArr[g_iTotalConn - 1];}g_pPerIODataArr[--g_iTotalConn] = NULL;}

阅读全文
0 0