windows Socket编程之重叠IO模型
来源:互联网 发布:联通小米3支持4g网络吗 编辑:程序博客网 时间:2024/04/19 08:41
上一篇文章我们讲了EventSelect网络模型,它已经解决了等待数据到来的这一大部分时间,但是它还有一小部分时间没有节省下来。那就是把数据从网卡的缓冲区拷贝到我们应用程序的缓冲区里边。而这一篇的重叠IO模型就是将这一小部分的时间也给节省了下来。
首先,我们在主线程里边初始化网络环境,然后创建监听的socket,接下来,执行绑定,监听的操作,然后,创建一个工作者线程来对客户进行服务。执行以上操作之后呢,是一个死循环。在这个循环里边,我们首先调用accept函数来对一个客户进行连接操作。然后将该函数返回的客户端的socket保存到我们定义的一个全局socket数组里边进去。然后对我们自定义的结构体单IO操作分配一个空间,其声明如下:
typedef struct{ WSAOVERLAPPED overlap;<span style="white-space:pre"></span>//OVERLAPPED结构,该结构里边有一个event事件对象 WSABUF Buffer;<span style="white-space:pre"></span>//WSABUF结构,里边有一个buf的大小,还有一个指针指向buf char szMessage[MSGSIZE];<span style="white-space:pre"></span>//消息数据 DWORD NumberOfBytesRecvd;<span style="white-space:pre"></span>//保存接收到的字节数 DWORD Flags;<span style="white-space:pre"></span>//标志位}PER_IO_OPERATION_DATA, *LPPER_IO_OPERATION_DATA;注意,该结构体是我们自己定义的,其中第一个参数overlapped结构体是最重要的,必须把它放在第一个声明处。因为我们要的是overlapped的地址,而其它的则是我们自己进行扩展的,大家也可以进行自己的扩展。那什么叫做单IO操作呢,比如说你请了一个人来专门打理你的店铺,你每天呢都会发一个信息给这个人,信息的内容就是叫他每天干一些指定的的事情,而这个信息就是我们这个单IO操作这个数据结构所指定的内容。
我们在堆上给我们的单IO结构分配完空间之后呢,我们来对它进行初始化,我们把Buffer里面的指针指向szMessage,把里面的大小指定为szMessage的大小。然后,调用WSACreateEvent创建一个事件对象,将这个事件对象赋予给overlappped里边的事件对象。
最后,在循环的末尾我们调用WSARecv,来对数据进行接收,其声明如下:
int WSARecv( SOCKET s, <span style="white-space:pre"></span>//客户连接的socket LPWSABUF lpBuffers, <span style="white-space:pre"></span>//WSABUFFER指针 DWORD dwBufferCount, <span style="white-space:pre"></span>//Buffer的个数,一般这里给个1 LPDWORD lpNumberOfBytesRecvd, <span style="white-space:pre"></span>//接收的字节数 LPDWORD lpFlags, <span style="white-space:pre"></span>//标志位 LPWSAOVERLAPPED lpOverlapped, <span style="white-space:pre"></span>//overlaopped结构地址 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine <span style="white-space:pre"></span>//没啥用,为NULL);注意,该函数是异步的,也就是说它调用完就直接进行返回了,不用等待。所以整个循环,只有刚开始接收到一个客户的连接之后,我们就畅通无阻的往下执行一遍,然后再回到循环的开始继续等待客户的连接。接下来,看下工作者线程。
工作者线程,也是一个死循环,它和我们的EventSelect一样,刚开始也是调用了WSAWaitForMultipleEvents,来监控我们的socket数组哪一个有信号了,由于这个函数最多只能监控64个socket,所以我们的服务端只能同时进行64个客户的数据收发。调用完该函数之后,它会返回一个索引值,我们将调用WSAResetEvent,将我们全局event数组里边那个有信号的手动重置为无信号状态。因为我们用WSACreateEvent创建的事件对象是以手动重置的方式创建的。如果,不重置成无信号的状态,那么就像上面我们举得那个例子一样,我们请的那个人,他第二天查看信息的时候,还会继续的执行昨天的工作。
接下来,是我们重叠IO模型里边和EventSelect里边最大的不同点,我们会调用WSAGetOverlappedResult,来判断重叠IO调用是否成功,其声明如下:
BOOL WSAGetOverlappedResult( SOCKET s, //有信号的那个socket LPWSAOVERLAPPED lpOverlapped, //overlapped结构地址 LPDWORD lpcbTransfer, //接收的字节数 BOOL fWait, //TRUE表示操作完成就返回 LPDWORD lpdwFlags //标志位);这个函数的第三个参数和我们的WSARecv的第四个参数是一样的,操作系统会改写这个值,若该值为0表示客户端断开连接或该数据传输失败了。如果没有失败,我们就将数据保存到我们那个单IO结构里边的szMessage数组里边。然后再次调用WSARecv,告诉操作系统继续帮我们监控这个socket。
以下是重叠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;}typedef struct{ WSAOVERLAPPED overlap; WSABUF 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(LPVOID);void Cleanup(int);int main(){SOCKET sListen, sClient;SOCKADDR_IN local, client;DWORD dwThreadId;int iaddrSize = sizeof(SOCKADDR_IN);// 初始化环境WinSockInit();// 创建监听socketsListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 绑定local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);local.sin_family = AF_INET;local.sin_port = htons(PORT);bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));// 监听listen(sListen, 3);// 创建工作者线程CreateThread(NULL, 0, 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)); //初始化单io结构 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(); // 开始一个异步操作 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); g_iTotalConn++;}closesocket(sListen);WSACleanup();return 0;}DWORD WINAPI WorkerThread(LPVOID lpParam){int ret, index;DWORD cbTransferred;while (TRUE){//判断是否有信号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{//将数据保存到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;}
- windows Socket编程之重叠IO模型
- 【Windows网络编程】重叠IO网络模型
- Windows socket之重叠IO:事件通知
- Windows socket之重叠IO:事件通知
- Windows socket之重叠IO:事件通知
- Socket编程模型之重叠IO(Overlapped I/O)模型
- WINDOWS重叠IO模型
- WINDOWS重叠IO模型
- WINDOWS重叠IO模型
- Windows socket-重叠模型
- Socket网络编程学习之路 第五篇 ----winsock网络IO模型(2)之 重叠IO模型
- socket之重叠io
- socket编程之IO模型
- Windows Socket IO 模型
- Windows Socket IO 模型
- Windows Socket IO 模型
- Windows Socket IO 模型
- Windows Socket IO 模型
- 数据结构实验之查找四:二分查找 (sdut oj 3376)
- 一个封装得比较好的上传文件代码
- Mongodb学习使用手册
- 洛谷1967 火车运输
- 你上班价值的在哪里?
- windows Socket编程之重叠IO模型
- Constexpr and Constant Expressions
- POJ2606 Rabbit hunt
- hdu3555 Bomb(数位dp)
- 数据结构实验之串一:KMP简单应用
- UVA-10200(素数)
- java中else if比switch效率低的原因
- 神经网络识别车牌字符
- 对比JAVA学习PHP系列:流程控制与异常处理