首先说明,下面的代码仅是一个IOCP的demo,很多地方的设计非常差,当然也有一些设计还算可以:)。此篇仅供对IOCP有些了解但又不深入的、需要一个稍微完整示例的、对网络编程感兴趣的同学参考。点击这里下载代码

整个程序的流程如下:

流程完全是无阻塞的,主线程里,将收到的消息全都一次性取出后,然后派发。所有欲发送的消息都缓存起来,等到更新的时候一起发送。有些地方代码没有完善,比如断开连接后,socket、内存等资源的关闭回收。要注意MAXRECEIVEDBUFFLENGTH这个宏,它是定义每个socket消息收发时缓冲区的大小。如果很大,会非常吃内存的。我在这里也没有做粘包、分包的情况处理。工程还带了一个C#写的测试客户端。在我的机器上,能有12W的连接。

关键代码如下:

void MyIOCP::Execute()
{
PerHandleData* pPerHandleData = nullptr;
PerIOData* pPerIOData = nullptr;
LPOVERLAPPED lpOverLapped = nullptr;
DWORD byteTransferred;
BOOL bRet = FALSE; while (true)
{
bRet = GetQueuedCompletionStatus(mCompletionPort,
&byteTransferred,
(PULONG_PTR)&pPerHandleData,
/*(LPOVERLAPPED*)&pPerIOData*/&lpOverLapped,
INFINITE);
pPerIOData = (PerIOData*)CONTAINING_RECORD(lpOverLapped, PerIOData, overlapped);
if (bRet == FALSE)
{
if (pPerIOData == nullptr)
{
// 退出线程。服务器要关了。。
break;
}
// 对方主动断开了 continue;
} // 处理成功的完成端口请求
switch (pPerIOData->operationType)
{
case CDH::E_INVALID:
{
}
break;
case CDH::E_ACCEPT:
{
/************************************************************************/
/*
inet_ntoa(ClientAddr->sin_addr) 是客户端IP地址 ntohs(ClientAddr->sin_port) 是客户端连入的端口 inet_ntoa(LocalAddr ->sin_addr) 是本地IP地址 ntohs(LocalAddr -AZ>sin_port) 是本地通讯的端口 pIoContext->m_wsaBuf.buf 是存储客户端发来第一组数据的缓冲区
*/
/************************************************************************/
SOCKADDR_IN* ClientAddr = NULL;
SOCKADDR_IN* LocalAddr = NULL;
int remoteLen = sizeof(SOCKADDR_IN), localLen = sizeof(SOCKADDR_IN);
mlpfnGetAcceptExSockAddrs(pPerIOData->buffer, , sizeof(SOCKADDR_IN)+, sizeof(SOCKADDR_IN)+, (LPSOCKADDR*)&LocalAddr, &localLen, (LPSOCKADDR*)&ClientAddr, &remoteLen); WrapSocket* connectedSocket = GetSocketAndEraseFromTheMap(pPerIOData->remoteSocket, WRAPESOCKETTYPE::E_READYTOBECONNECTED);
if (connectedSocket == nullptr)
{
closesocket(pPerIOData->remoteSocket);
continue;
}
if (!AssociateDeviceWithCompletionPort(connectedSocket))
{
closesocket(pPerIOData->remoteSocket);
continue;
}
// 添加到已经连接列表
InsertWrapSocketToMap(connectedSocket, WRAPESOCKETTYPE::E_CONNECTED); PostReceive(connectedSocket); // 这次消耗了一个准备好了的socket, 现在再生成一个socket待连接。
PostAcceptEx(connectedSocket->GetPerHandleData().hasListenSocket);
}
break;
case CDH::E_RECV:
{
int socket = pPerHandleData->selfSocket;
WrapSocket* wrapSocket = nullptr;
GetSocketForSendOrRecvData(socket, wrapSocket); if (wrapSocket != nullptr)
{
wrapSocket->GetPerIODataReceive().bufferLen = byteTransferred;
Receive(wrapSocket);
}
}
break;
case CDH::E_SEND:
{
int socket = pPerHandleData->selfSocket;
WrapSocket* wrapSocket = nullptr;
GetSocketForSendOrRecvData(socket, wrapSocket);
if (wrapSocket != nullptr)
{
wrapSocket->SendingData(false);
} }
break;
case CDH::E_CONNECT:
break;
default:
break;
} }
}

注意CDH::E_RECV,收到消息后,将消息缓存,然后直接又进行投递PostReceive(),这其实是非常不好的。应该分情况来选择是否立即投递。

以上,整个代码,基本是用C++的格式写C代码。希望以后能有机会与大家共同分享一个比较完整的、面向对象风格的IOCP。

分享我写的IOCP:源码+思路的更多相关文章

  1. 【学】jQuery的源码思路1——后代选择器

    jQuery的源码思路1--后代选择器 这里探讨一下jQuery中后代选择器的封装原理,并自己写一下 getEle('#div1 ul li .box');接受的参数就是个后代选择器,类似于这样: # ...

  2. 手写Koa.js源码

    用Node.js写一个web服务器,我前面已经写过两篇文章了: 第一篇是不使用任何框架也能搭建一个web服务器,主要是熟悉Node.js原生API的使用:使用Node.js原生API写一个web服务器 ...

  3. 手写@koa/router源码

    上一篇文章我们讲了Koa的基本架构,可以看到Koa的基本架构只有中间件内核,并没有其他功能,路由功能也没有.要实现路由功能我们必须引入第三方中间件,本文要讲的路由中间件是@koa/router,这个中 ...

  4. 【学】jQuery的源码思路2——$符号是如何封装的

    jQuery中的$符号功能很强大,原因在于对函数参数的个数以及种类的控制,还有对于面向对象思想的运用 function jQuery(args){ //接受参数,并对其判断 this.elements ...

  5. 分享45个android实例源码,很好很强大

    分享45个android实例源码,很好很强大 http://www.apkbus.com/android-20978-1-1.html 分享45个android实例源码,很好很强大http://www ...

  6. C写的扫描器源码

    Title:C写的扫描器源码 --2010-10-27 20:02 无意间看见的一个源代码,弄回来读下. ----------------------------------------------- ...

  7. 分享45个android实例源码,很好很强大.收藏吧!!!

    andriod闹钟源代码 http://www.apkbus.com/android-20974-1-1.html android源码分享之指南针程序 http://www.apkbus.com/an ...

  8. Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)

    Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)    转 https://blog.csdn.net/lhl1124281072/article/details/800 ...

  9. 【腾讯Bugly干货分享】微信iOS SQLite源码优化实践

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57b58022433221be01499480 作者:张三华 前言 随着微信iO ...

  10. 手写Express.js源码

    上一篇文章我们讲了怎么用Node.js原生API来写一个web服务器,虽然代码比较丑,但是基本功能还是有的.但是一般我们不会直接用原生API来写,而是借助框架来做,比如本文要讲的Express.通过上 ...

随机推荐

  1. Communications link failure报错的处理

    一.报错的问题: 测试环境在做压力测试的时候爆出错误 com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications l ...

  2. 【Android 应用开发】Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载

    19af543b068bdb7f27787c2bc69aba7f Additional Download (32-, 64-bit) Package r10 STL debug info androi ...

  3. Windows 7系统安装MySQL5.5.21图解

    Win7系统安装MySQL5.5.21图解 大家都知道MySQL是一款中.小型关系型数据库管理系统,非常具有有用性,对于我们学习非常多技术都有帮助,前几天我分别装了SQL Server 2008和Or ...

  4. TCP/IP协议知识科普

    简介 本文主要介绍了工作中常用的TCP/IP对应协议栈相关基础知识,科普文. 本博客所有文章:http://www.cnblogs.com/xuanku/p/index.html TCP/IP网络协议 ...

  5. Linux内核加载全流程

    无论是Linux还是Windows,在加电后的第一步都是先运行BIOS(Basic Input/Output System)程序——不知道是不是所以的电脑系统都是如此.BIOS保存在主板上的一个non ...

  6. Helpers\PHPMailer

    Helpers\PHPMailer PHPMailer is a third party class for sending emails, Full docs are available athtt ...

  7. Linux命令之hwclock

    转载:http://codingstandards.iteye.com/blog/804830 用途说明 hwclock命令,与clock命令是同一个命令,主要用来查询和设置硬件时钟(query an ...

  8. javascript 十六进制与RGB颜色值的相互转换

    http://www.zhangxinxu.com/wordpress/?p=646 http://www.zhangxinxu.com/wordpress/?p=646 -------------- ...

  9. const ;static;extern的使用与作用

     const                                                                /**      const :常量      const  ...

  10. CSS code snip enjoy.

    <!-- information-total得是动态获取吧. --> <div class="information-mod"> <div class ...