分享我写的IOCP:源码+思路

首先说明,下面的代码仅是一个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, 0, sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, (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:源码+思路,布布扣,bubuko.com

时间: 2024-11-01 01:14:09

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

分享》:关于阅读开源项目的源码思路方法

关于阅读开源项目的源码思路方法:<不喜勿喷> 一般开源项目, 如果这个项目你很熟悉经常用, 那么你直接从 main 入手没问题.. 如果你不熟悉或者代码量很大, 最好从代码的 example 代码 或者 client 的代码入手比较容易. 这些代码直接 gdb 进去就可以调试运行了, 客户端的功能搞清楚了,会用了, 恐惧感就降下去了, 再看服务端就容易了. 看 c 代码要 关注主体核心 struct , 整个server, client 可能都是围绕整个 struct 运行起来的, 这个str

ajaxFileupload的源码思路分析

? 1 ajaxfileupload源码: jQuery.extend({ //创建一个临时的iframe; createUploadIframe: function(id, uri) { //create frame var frameId = 'jUploadFrame' + id; var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="posit

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

分享45个android实例源码,很好很强大http://www.apkbus.com/android-20978-1-1.html andriod闹钟源代码http://www.apkbus.com/android-20974-1-1.html android源码分享之指南针程序http://www.apkbus.com/android-20973-1-1.html 重力感应的测试程序andriod源代码http://www.apkbus.com/android-20972-1-1.html

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

andriod闹钟源代码http://www.apkbus.com/android-20974-1-1.htmlandroid源码分享之指南针程序http://www.apkbus.com/android-20973-1-1.html重力感应的测试程序andriod源代码http://www.apkbus.com/android-20972-1-1.htmlandroid源码分享之时光日志个人日程管理http://www.apkbus.com/android-20969-1-1.htmlOpen

礼物说仿写项目iOS源码

礼物说仿写(updating...) 源码下载:http://code.662p.com/view/14507.html api: 礼物说 首页精选 banner2: http://api.liwushuo.com/v2/secondary_banners?gender=1&generation=2 banner1: http://api.liwushuo.com/v2/banners?channel=iOS 精选: http://api.liwushuo.com/v2/channels/101

C写的扫描器源码

Title:C写的扫描器源码 --2010-10-27 20:02 无意间看见的一个源代码,弄回来读下. ----------------------------------------------------------------------------------------------------------------------------------- #include <stdio.h>#include <winsock.h> #define NETWORK_ERR

分享12306秒票杀手锏源码

本案通过切换地点和CDN,相对于识别验证码.开多浏览器,更能第一时间出票,从本质上解决刷票的问题.       由于是杀手锏,一旦大面积使用,容易TDB封锁.但考虑到很多人问起,暂时放出核心代码供大家一起研究: 源码下载:http://files.cnblogs.com/guozili/12306.rar 必备1:Firefox(V20以上有问题) + Greasemonkey + HostAdmin 必备2:本地架IIS .net 4.0网站切hosts 原理1:如果(广州,广州南,广州北)

【重播工具箱】MTK全方案手机端APP,一键备份自动生成线刷包 源码思路解析

这个是本人MTK工具箱,在 5月份的时候,发布的..功能可能说是全球首发把,第一个手机MTK的一键备份工具,而且是兼容MTK全方案.MTK6589 MTK6592 6575 82等, 现在将源码以及思路,分享给大家,有兴趣的可以看看. 源码解析以及思路,待发布....... 分享地址:http://www.592zn.com/thread-311286-1-1.html 下载地址http://pan.baidu.com/s/1hqeethy重大更新: 1.手机端首发,备份MTK系列全自动,生成线

随手用python写一个下载源码爬虫试试

最近在研读jdk源码,网上找了下资源,发现都不完整. 后来新发现了一个有完整源码的地方,主要包括了java,c,c++的东西,装逼需要,就想拿来玩玩.但是,找了好多种下载打开的方式,发现都不对.于是,我随手写了python爬虫,把他搞定. 1. 思路分析 1.1. 目标地址:http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/dddb1b026323/,打开后先自己看下,是否符合自己的需求: 1.2. 分析此结构下主要有两种形式,一是目录文件,二是最终