博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单的实现IOCP服务器模型
阅读量:6503 次
发布时间:2019-06-24

本文共 4251 字,大约阅读时间需要 14 分钟。

其实已经有很多大佬将原理讲的十分详细了,所以就不花费时间将原理再一次重复讲一遍,有需要的可以自行去查看。

http://blog.csdn.net/beyond_cn/article/details/9336043 这篇文章是我看的,原理介绍十分详细。不过有一些操作感觉比较复杂因此我简化了许多。还是要感谢大佬们倾力普及知识

IOCP模型的关键呢就是将完成端口与套接字绑定起来,然后在这个套接字上投递一个接收请求。然后工作线程得到通知,从缓冲区中取出数据(完成端口已经帮我们将数据从套接字中取到缓冲区,要知道这一步是挺耗时的,所以节省了挺多时间)。我在实现的时候就会有疑问:工作线程仅仅取到数据就好吗?因为我肯定得知道是从哪个套接字中取到的,以便接下来可以接着投递接收请求以及发送请求。那么关键就是在于你绑定完成端口与套接字函数CreateIoCompletionPort()的第三个参数。这个参数我传进去的是一个指针,指针指向的结构体包含了套接字、缓冲区等等内容(这意味着你的这个结构体需要放在堆里面能够被多个线程访问到,这里我用GlobalAlloc)。然后在工作线程使用GetQueuedCompletionStatus()从第三个参数中就能获得你传进去的那个指针的地址,你就可以通过这个地址获得指针进而访问到传进去的结构体。当然也有比较简单的办法就是利用全局变量,然后你在CreateIoCompletionPort()传入的是i(标识符),标明这个是第几个。然后从对应的一系列数组获得你想要的信息。最好的话还是建一个结构体,把需要的东西都打包在一起。

要正常工作起来的话需要注意WSARecv中传入的wsabuf需要初始化好,包括其buf和len。我就是因为len没初始化只初始化了buf导致之前一直失败。

 

//IOCP代码#pragma comment(lib, "ws2_32.lib")#include 
#include
#include
using namespace std;#define DATA_BUFSIZE 1024SOCKET ListenSocket;struct PerIOcontext{ OVERLAPPED m_Overlapped; SOCKET m_sockAccept; WSABUF m_wsaBuf; char buffer[DATA_BUFSIZE];};DWORD WINAPI AcceptThread(LPVOID lpParameter){ WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); ListenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED); SOCKADDR_IN ServerAddr; ServerAddr.sin_family = AF_INET; ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); ServerAddr.sin_port = htons(1234); bind(ListenSocket, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr)); listen(ListenSocket, 100); printf("listenning...\n"); int i = 0; SOCKADDR_IN ClientAddr; int addr_length = sizeof(ClientAddr); HANDLE completionPort = (HANDLE)lpParameter; while(TRUE) { PerIOcontext* perIOcontext = (PerIOcontext*)GlobalAlloc(GPTR, sizeof(PerIOcontext)); SOCKET acceptSocket; SOCKADDR_IN acceptAddr; int len = sizeof(acceptAddr); acceptSocket = accept(ListenSocket, (SOCKADDR*)&acceptAddr, &len); printf("接受到客户端连接"); if(SOCKET_ERROR == perIOcontext->m_sockAccept){ // 接收客户端失败 cerr << "Accept Socket Error: " << GetLastError() << endl; system("pause"); return -1; } perIOcontext->m_wsaBuf.buf = perIOcontext->buffer; perIOcontext->m_wsaBuf.len = 1024; perIOcontext->m_sockAccept = acceptSocket; CreateIoCompletionPort((HANDLE)(perIOcontext->m_sockAccept), completionPort, (DWORD)perIOcontext, 0); DWORD RecvBytes; DWORD Flags = 0; ZeroMemory(&(perIOcontext->m_Overlapped), sizeof(OVERLAPPED)); WSARecv(perIOcontext->m_sockAccept, &(perIOcontext->m_wsaBuf), 1, &RecvBytes, &Flags, &(perIOcontext->m_Overlapped), NULL); } return FALSE;}DWORD WINAPI ReceiveThread(LPVOID lpParameter){ HANDLE completionPort = (HANDLE)lpParameter; DWORD BytesTransferred; PerIOcontext* perIOcontext; LPOVERLAPPED IpOverlapped = NULL; while(true) { printf("Receive线程进入等待\n"); BOOL ret = GetQueuedCompletionStatus(completionPort, &BytesTransferred, (PULONG_PTR)&perIOcontext, &IpOverlapped, INFINITE); printf("Receive线程退出等待\n"); if (BytesTransferred == 0) { printf("获得字节为0,disconnect\n"); } printf("客户端:%s\n", perIOcontext->buffer); memset(perIOcontext->buffer, 0, DATA_BUFSIZE); DWORD RecvBytes; DWORD Flags = 0; system("pause"); WSARecv(perIOcontext->m_sockAccept, &(perIOcontext->m_wsaBuf), 1, &RecvBytes, &Flags, &(perIOcontext->m_Overlapped), NULL); } return FALSE;}int main(){ HANDLE completionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0); if (NULL == completionPort){ // 创建IO内核对象失败 cout << "CreateIoCompletionPort failed. Error:" << GetLastError() << endl; system("pause"); return 0; } HANDLE hThreads[2]; hThreads[0] = CreateThread(NULL, 0, AcceptThread, completionPort, NULL, NULL); hThreads[1] = CreateThread(NULL, 0, ReceiveThread, completionPort, NULL, NULL); WaitForMultipleObjects(2, hThreads, TRUE, INFINITE); printf("exit\n"); CloseHandle(hThreads[0]); CloseHandle(hThreads[1]); return 0;}

 

转载于:https://www.cnblogs.com/joshtao/p/7381316.html

你可能感兴趣的文章
Java基础学习总结(1)——equals方法
查看>>
Maven学习总结(6)——Maven与Eclipse整合
查看>>
HTML5:理解head
查看>>
oracle
查看>>
java SpringUtil获取bean
查看>>
Centos6.4最小化安装系统初始化脚本
查看>>
PaaS变厚了
查看>>
赛门铁克开启“容灾即服务”时代
查看>>
复杂度归纳--小结
查看>>
PHP学习笔记 第八讲 Mysql.简介和创建新的数据库
查看>>
【git】git入门之把自己的项目上传到github
查看>>
js获取鼠标位置
查看>>
2016.8.11 DataTable合并及排除重复方法
查看>>
php 魔术方法 说明
查看>>
Mysql
查看>>
POJ-1860-Currency Exchange
查看>>
跨越企业的“中等收入陷阱”
查看>>
Android 开发者必知的开发资源
查看>>
软件工程技术基础-(软件复用技术)
查看>>
给django视图类添加装饰器
查看>>