WINDOWS 2000以后的操作系统才支持IOCP。WINSOCK2.0才支持IOCP。

首先要有一个WINSOCK2.PAS的WINSOCK2.0接口调用声明单元。

WINSOCK的版本号: WINSOCK_VERSION = $0202;

动态库:ws2_32 = 'ws2_32.dll';

1)服务端首先要创建一个监听SOCKET,用于监听客户端连接。

1.1)加载WINSOCK2协议

if WSAStartup($0202, WsaData) <> 0 then
raise ESocketError.Create(GetLastWsaErrorStr);

1.2)创建服务端监听SOCKET

VAR FSocket: TSocket;

FSocket := WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED);
if FSocket = INVALID_SOCKET then
raise ESocketError.Create(GetLastWsaErrorStr);

1.3)为创建的服务端监听SOCKET准备IP地址,端口号。。。

var Addr: TSockAddr;

FillChar(Addr, SizeOf(Addr), 0);
Addr.sin_family := AF_INET;
Addr.sin_port := htons(FPort);
Addr.sin_addr.S_addr := htonl(INADDR_ANY); //在任何地址上监听,如果有多块网卡,会每块都监听

1.4)为服务端监听SOCKET绑定

if bind(FSocket, @Addr, SizeOf(Addr)) <> 0 then
raise ESocketError.Create(GetLastWsaErrorStr);

1.5)在服务端监听SOCKET上开启监听

if listen(FSocket, MaxInt) <> 0 then
raise ESocketError.Create(GetLastWsaErrorStr);

1.6)服务端监听线程。当然也可以在主线程执行一个WHILE循环不停地接收客户端的连接,但使用监听线程显然更好。

var
ClientSocket: TSocket;

ClientSocket := WSAAccept(FSocket, nil, nil, nil, 0);  // FSocket就是前面已经创建好的服务端监听SOCKET

if ClientSocket <> INVALID_SOCKET then begin

PostQueuedCompletionStatus(FIocpHandle, 0, ClientSocket, nil); // 客户端连接被提交到完成端口队列中

end;

2)IOCP

2.1)创建完成端口。

var FIocpHandle: THandle;

FIocpHandle := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if FIocpHandle = 0 then
raise ESocketError.Create(GetLastErrorStr);

2.1)将客户端连接和IOCP绑定

var cSocket: PClientSocket;

CreateIoCompletionPort(ClientSocket, FIOCPHandle, DWORD(cSocket), 0);

2.2)接收客户端数据

type
{* 完成端口操作定义 *}
TIocpOperate = (ioNone, ioRead, ioWrite, ioStream, ioExit);
PIocpRecord = ^TIocpRecord;
TIocpRecord = record
Overlapped: TOverlapped; //完成端口重叠结构
WsaBuf: TWsaBuf; //完成端口的缓冲区定义
IocpOperate: TIOCPOperate; //当前操作类型
end;

var FIocpRecv: PIocpRecord;

iFlags, iTransfer: Cardinal;

FIocpRecv.Overlapped.Internal := 0;
FIocpRecv.Overlapped.InternalHigh := 0;
FIocpRecv.Overlapped.Offset := 0;
FIocpRecv.Overlapped.OffsetHigh := 0;
FIocpRecv.Overlapped.hEvent := 0;
FIocpRecv.IocpOperate := ioRead;
iFlags := 0;

WSARecv(FSocket, @FIocpRecv.WsaBuf, 1, iTransfer, iFlags, @FIocpRecv.Overlapped, nil);

3)工作线程处理接收到的客户端数据

3.1)工作线程是最繁忙,服务器上CPU的数量决定了工作线程的数量,CPU数量越多可以创建的工作线程数量也就越多。

TClientSocket = record
Lock: TCriticalSection;
SocketHandle: TSocketHandle;
IocpRecv: TIocpRecord; //投递请求结构体
IdleDT: TDateTime;
end;
PClientSocket = ^TClientSocket;

var
ClientSocket: PClientSocket;
IocpRecord: PIocpRecord;
iWorkCount: Cardinal;

GetQueuedCompletionStatus(FIocpHandle, iWorkCount, DWORD(ClientSocket), POverlapped(IocpRecord), INFINITE);

IOCP大致的流程就是这样,当然服务端发送数据给客户端的代码此处省略,相信读者根据接收代码已经知道怎么弄了。

IOCP为我们提供了一个系统级的消息队列(称之为完成队列),事件循环就是围绕着这个完成队列展开的。在发起IO操作后系统会进行异步处理(如果能立刻处理的话也会直接处理掉),当操作完成后自动向这个队列投递一条消息,不管是直接处理还是异步处理,最后总会投递完成消息。

IOCP完成队列返回的消息是一个OVERLAPPED结构体和一个ULONG_PTR complete_key。complete_key是在用户将Socket handle关联到IOCP的时候绑定的,其实用性不是很大,而OVERLAPPED结构体则是在用户发起IO操作的时候设置的,并且OVERLAPPED结构可以由用户通过继承的方式来扩展,因此如何用好OVERLAPPED结构在螺丝壳里做道场,就成了封装好IOCP的关键。

完成端口iocp——在螺丝壳里做道场的更多相关文章

  1. 完成端口IOCP详解

    修改自: http://blog.csdn.net/piggyxp/article/details/6922277 ps: 原作者很厉害了, 把一个iocp模型讲解的这么形象,不过在实践过程中发现一些 ...

  2. HDU 2795 Billboard(区间求最大值的位置update的操作在query里做了)

    Billboard 通过这题,我知道了要活用线段树的思想,而不是拘泥于形式, 就比如这题 显然更新和查询放在一起很简单 但如果分开写 那么我觉得难度会大大增加 [题目链接]Billboard [题目类 ...

  3. 教你在Excel里做GA的水平百分比图的详细步骤(图文教程)-成为excel大师(1)

    GA报表除了默认的表格方式显示数据外,还支持饼图,水平百分比图,数据透视图等展现方式,其中水平百分比图在可视化看流量时最为方便,就像这样: 那么当我们要在Excel里做类似的效果应该怎么做呢?尤其是数 ...

  4. DELPHI中完成端口(IOCP)的简单分析(4)

    DELPHI中完成端口(IOCP)的简单分析(4)   在我以前写的文章中,一直说的是如何接收数据.但是对于如何发送数据却一点也没有提到.因为从代码量上来说接收的代码要比发送多很多.今天我就来写一下如 ...

  5. DELPHI中完成端口(IOCP)的简单分析(3)

    DELPHI中完成端口(IOCP)的简单分析(3)   fxh7622关注4人评论7366人阅读2007-01-17 11:18:24   最近太忙,所以没有机会来写IOCP的后续文章.今天好不容易有 ...

  6. DELPHI中完成端口(IOCP)的简单分析(2)

    DELPHI中完成端口(IOCP)的简单分析(2)   今天我写一下关于DELPHI编写完成端口(IOCP)的工作者线程中的东西.希望各位能提出批评意见.上次我写了关于常见IOCP的代码,对于IOCP ...

  7. DELPHI中完成端口(IOCP)的简单分析(1)

    DELPHI中完成端口(IOCP)的简单分析(1)   用DELPHI开发网络代码已经有一段时间了! 我发现在网上用VC来实现完成端口(IOCP)的代码很多,但是使用DELPHI来实现的就比较少了.对 ...

  8. Qt5 UI信号、槽自动连接的控件重名大坑(UI生成的槽函数存在一个隐患,即控件重名。对很复杂的控件,不要在 designer 里做提升,而是等到程序启动后,再动态创建,可以避免很多问题)

    对Qt5稍有熟悉的童鞋都知道信号.槽的自动连接机制.该机制使得qt designer 设计的UI中包含的控件,可以不通过显式connect,直接和cpp中的相应槽相关联.该机制的详细文章见 http: ...

  9. ASP.NET Core如何在ActionFilterAttribute里做依赖注入

    在ASP.NET Core里,我们可以使用构造函数注入很方便地对Controller,ViewComponent等部件做依赖注入.但是如何给过滤器ActionFilterAttribute也用上构造函 ...

随机推荐

  1. [ionic开源项目教程] - 第15讲 ionic用户个人中心登录注册的实现

    第15讲 ionic用户个人中心登录注册的实现 这一讲包括登陆.注册.个人中心.个人资料页面的实现. 在一讲的改动有四个地方: 在config.js里配置接口地址 完善个人中心的服务层(service ...

  2. linux修改文件夹及其子文件夹的权限

    加入-R 参数,就可以将读写权限传递给子文件夹例如chmod -R 777 /home/mypackage那么mypackage 文件夹和它下面的所有子文件夹的属性都变成了777.777是读.写.执行 ...

  3. PHP学习笔记06——面向对象版图形计算器

    index.php 用于显示页面 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "h ...

  4. 如何添加真机调试的iOS设备

    注意点: 有时需要同意协议什么的,很多时候刷新出来都是白屏,解决办法: 对于不能确认新协议的问题,我发现了一个解决方法:登陆后,直接在浏览器的地址框访问:https://developer.apple ...

  5. KM算法(二分图的最佳完美匹配)

    KM算法大概过程: (1)初始化Lx数组为该boy的一条权值最大的出边.初始化Ly数组为 0. (2)对于每个boy,用DFS为其找到一个girl对象,顺路记录下S和T集,并更新每个girl的slac ...

  6. 同步内核缓冲区sync、fsync和fdatasync函数

    转自http://www.2cto.com/os/201409/339460.html 同步内核缓冲区 1.缓冲区简介 人生三大错觉之一:在调用函数write()时,我们认为该函数一旦返回,数据便已经 ...

  7. 【Java】从域名得到ip

    package sdfg; import java.net.InetAddress; //import java.net.UnknownHostException; import java.io.*; ...

  8. poj 1986 Distance Queries

    好像是模板题  当作练习题 不错:  要求任意两点之间的距离.可以假设一个根节点,然后所有点到根节点的距离,然后求出任意两点多公共祖先:  距离就变成了 dis[u]+dis[v] - 2*dis[ ...

  9. Heritrix源码分析(二) 配置文件order.xml介绍(转)

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/613412      本博客已迁移到本人独立博客: http://www.yun5u. ...

  10. Android之Socket群组聊天

    在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息 贴一下Androi ...