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

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 <WinSock2.h>
#include <stdio.h>
#include <iostream>
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

简单的实现IOCP服务器模型相关推荐

  1. 简单谈谈select, iocp, epoll,kqueue及各种I/O复用机制

    [本文转载于再谈select, iocp, epoll,kqueue及各种I/O复用机制] 首先,介绍几种常见的I/O模型及其区别,如下: blocking I/O nonblocking I/O I ...

  2. IOCP 网络通讯模型源码解读

    From: http://hi.baidu.com/tsingsing/item/1aa5062fa27791fa50fd87b7 以前写服务器的时候用的是iocp,最近偶然发现windows的 网络 ...

  3. 基于Delphi的Socket I/O模型全接触

    老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系.他们的信会被邮递员投递到他们的信箱里. 这和Socket模型非常类似.下面我就以老陈接收信件为例讲解Socket I/O模型. 一:se ...

  4. 很幽默的讲解六种Socket IO模型

    很幽默的讲解六种Socket IO模型   本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSel ...

  5. 5种IO模式形象的比喻

    老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系.他们的信会被邮递员投递到他们的信箱里. 这和Socket模型非常类似.下面我就以老陈接收信件为例讲解SocketI/O模型. 一:sel ...

  6. Socket I/O模型全接触

    声明:除CSDN外的任何媒体转载必须注明作者以及"转载自CSDN". 本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一 ...

  7. 很幽默的讲解六种Socket I/O模型C++程序设计

    本文简单介绍了当前Windows支持的各种Socket I/O模型,如果你发现其中存在什么错误请务必赐教. 一:select模型 二:WSAAsyncSelect模型 三:WSAEventSelect ...

  8. 【Linux Socket 编程入门】05 - 拉个骡子溜溜:TCP编程模型代码分析

    (一) 看看以前学了啥 前面介绍了socket的分类,IP地址,端口号(port),常用的socket数据结构以及常用的函数.现在我们来看一个例子,看看socket编程究竟是什么. (二) 一图看懂客 ...

  9. windows 多种 socket 模型的理解

    老陈有一个在外地工作的女儿,不能经常回来,老陈和她通过信件联系.他们的信会被邮递员投递到他们的信箱里. 这和Socket模型非常类似.下面我就以老陈接收信件为例讲解SocketI/O模型. 一:sel ...

最新文章

  1. Android自定义控件系列之基础篇
  2. 如何在sqlserver数据库表中建立复合主键
  3. 如何删除springboot中的子项目
  4. Mysql表分区的选择与实践小结
  5. php hash代码下载,PHP中的哈希表 hash_insert
  6. 假如程序员面试都说真话
  7. Python 格式化字符串
  8. 更改git提交显示的用户名
  9. unix 连接 mysql_UNIX域套接字连接mysql
  10. 面向对象9:方法的重写、super关键字、子类对象的实例化过程
  11. linux 主流 集群 软件,Linux 高可用(HA)集群之Pacemaker详解
  12. 网关支付、银联代扣通道、快捷支付、银行卡支付分别是怎么样进行支付的?...
  13. <<流畅的Python>>读书笔记--汇总
  14. 闭环整流电路matlab仿真,分享:基于双闭环的单相整流器原理简介及仿真验证
  15. 云计算基础架构实施要经历三个阶段
  16. 《游戏力》的读后感作文3600字
  17. Fixed-step size(Solver)、Sample time(模块)、Sample time(powergui)三者的辨析
  18. WebRTC语音对讲无声音
  19. jpa :配置一对多 Error accessing field 错误
  20. 《中国图书馆图书分类法》(第五版)详表(中图分类号查询表)

热门文章

  1. Json的序列化和反序列化
  2. 利用GridView显示主细表并一次编辑明细表所有数据的例子
  3. Banknote Dataset(钞票数据集)介绍
  4. C++中#error/assert/static_assert的区别及使用
  5. 【Qt】解决在linux上使用Qt的媒体模块(Qt += multimedia)缺少模块multimedia的问题
  6. 【Qt】Qt动态库和静态库的创建和使用
  7. pygame做的著名游戏_用python写游戏之2D跑酷游戏(一)
  8. python获取当前进程id_Python进程,多进程,获取进程id,给子进程传递参数操作示例...
  9. python跟java 效率_对比平台--Java与Python之间的性能差异
  10. 蘑菇模拟器TV版 for Android,安卓NES模拟器TV版下载