IOCP 完成端口的最简说明 - 附DELPHI源码

IOCP 完成端口最简说明

IOCP越说越复杂,我想尝试简明的从初学者的概念来说明,把最迷惑的部分简要说明:

关键点一:完成IO端口返回的消息,系统会自动保存在队列里!不是触发或者立刻返回!因为服务器需要快,所以完成端口自己先把处理好的消息全部保存到队列里!它不管你现在干嘛,只要合法的它都帮你存好!用不用你取出来再判断!所以我们关键的动作是从完成端口的队列去把消息取出来并处理!

关键点二:它的关键函数:到队列去取数据的函数,它是阻塞式的。你执行了这个函数,如果队列里没有消息,它会停住等到有消息之后才往下走(当然也可以设置马上往下走,但实际我们都会让它等,这是它效率高的关键)!所以大部分情况下,我们需要建立线程去执行从队列里取数据的动作!建立一个或者多个线程等待直到队列里有新消息并每次取出一条进行处理!多线程取的好处是取的更快(队列消息积压是糟糕的)

对,这是关键点!

简单来说只要3步

1)Var  WSData: TWSAData;

   WSAStartup($0202, WSData);  初始化库,后面才能调用相关完成端口函数,WSData用于判断是否初始化成功

2)var FIocpHandle: THandle;

   FIocpHandle:=CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 这里创建了一个完成IO端口并返回其句柄

此时我们的完成IO端口建好了!只是它暂时还没有输入源(也就是没绑定文件句柄)。

系统已经开始为我们准备好队列了,只是没有绑定输入源所以是没有消息进来的。

你已经可以去尝试队列取消息了,微软为我们取消息准备好了指定的函数,不过这个函数比较特别,需要特别注意,看下一步。

3)GetQueuedCompletionStatus(CompletionPort, BytesTransferred,

       ULONG_PTR(cSocket), POverlapped(PerIoData), INFINITE)

从消息队列取一个消息!第一个参数就是我们建立的完全IO端口,后面2个参数是返回消息的套接字信息,第三个是返回的数据,第四个参数是等待消息的时间,设置为INFINITE会无限时间等下去!

如前所说,这个函数是阻塞式的!当队列是空的,它就会停住等待!这个好处是节省CPU时间,坏处是我们要建立线程来执行它以免主线程阻塞。但是只要有新消息到,这个函数是马上完成并返回套接字信息和数据信息!所以可以看到,为什么每个解释完成端口的文章,都要说到线程!因为必须要建立线程来取完成端口的队列取处消息!建立的线程简单来说就是不断的执行这个函数!不用考虑任何东西,你就反复的执行这个命令来取消息来处理(根据你的业务需求处理收到的数据),没消息的话GetQueuedCompletionStatus会停住不消耗CPU时间。当然你对消息的处理越快你的服务器性能表现的越好,不过基本不用担心数据丢失!这个队列是很强大的。

完成端口建立好,消息队列也准备好了

下面需要为完成端口绑定输入的数据源(文件句柄),否则是没有消息进来的,消息队列会一直为空(这应该很好理解)。

对于TCP而言,需要跟客户端套接字完成握手后,才能收到消息。

建立服务器跟客户端的连接有如下三步:

1) WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED); 建立一个套接字

2)bind(FSocket, @Addr, SizeOf(Addr)) 把这个套接字跟端口(PORT)绑定,因为服务器基本都是固定一个端口的

3) listen(FSocket, MaxInt) 开始监听这个套接字看有没有客户端请求连接

这三步后,服务器会开始处理所有的连接,我们不用管,系统处理好的连接也会放到队列里面!!!

又是队列!!跟上面一样,我们需要建立线程来查看连接队列是不是有新的连接请求进来!

微软为我们提供查询连接队列的函数是 : WSAAccept  , 这个查看连接队列的函数跟GetQueuedCompletionStatus一样,当队列为空它会等下去!所以我们又要用线程来执行它,等到连接队列有新建立好的连接后,它才给我们返回跟客户端已经连接好的套接字。注意,是连接好的套接字,所以具体是怎么连接我们是不用处理的。

现在看来,整个完成端口,我们要做的,就是高效的的查收两个队列的信息并处理他们:  消息队列 和 连接队列。微软的设计是要求我们用线程去访问这两个队列的!所以对于完成端口模型的TCP,我们是需要设计两个线程来分别不断的访问这两个队列的。不过不用担心,如果消息队列为空,线程等待所消耗的CPU时间可以忽略不计!这就是完成端口的高效原因之一。

总结来说

WSAAccept  等待新的连接请求进队列,只要队列不为空马上取出一个处理

GetQueuedCompletionStatus 等待新的消息进队列,只要队列不为空马上取出一个处理

至于微软怎么做到这个等待不耗时我们基本不用管了。

WSAAccept查询连接队列,当队列有正确的连接请求(TCP在没有建立连接前是不接收任何其他信息的,所以我说这里是监听连接队列),WSAAccept会返回一个建立好的跟客户端对应的套接字,把这个套接字跟完成端口绑定,这样来自客户端的消息就会正确进入我们的完成端口队列了。这个绑定仍然是用前面创建完成端口的函数CreateIoCompletionPort,这次需要指定要绑定的完成端口和刚返回的客户端对应套接字。可以参考CreateIoCompletionPort函数的参数说明。

一个完成端口可以跟多个客户端套接字绑定(微软设计的客户端套接字也是可以复用的,尽量减少开套接字的开销)

整个接收完成了!!!

发送跟其他的模式没有特别的不同,这里不详细说。

根据我初学者的误区,我一直在找哪里触发连接、接收、断开的消息!不是的,真实的情况是我们需要建立线程来查询连接队列和接收消息队列!对,就是我们要处理的重点是怎么快速的从这两个队列里把消息取出来。并且需要再次强调,微软提供的从这两个队列取数据的函数,它在队列为空的时候会停住等待!所以实际应用中,建立线程来执行这两个函数是必须的。

好了,一个初学者理解到这,很多地方没有用微软给的专业名词只是为了更好的理解。

有错误理解的请告知我让我也改正。

根据这个理解写了基本没有多余的源码:一个完全端口对象,一个连接队列线程,一个信息队列线程,有些错误但可以运行了。需要的可告知。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用IOCP完成端口和Socket封装的异步TCP类是一种成熟的技术,它能够有效地处理大量并发请求,并且能够提高系统的性能和效率。首先,IOCP能够充分利用系统资源,通过将I/O操作交给内核来完成,可以实现高效的异步操作。而端口和Socket封装则可以简化开发者的编程工作,提供更加友好的接口和操作方法,从而提高开发效率和代码的可读性。 此外,使用IOCP完成端口和Socket封装的异步TCP类还具有良好的扩展性和灵活性。通过合理设计类的结构和接口,可以实现类的继承和重载,满足不同应用场景和需求。同时,IOCP完成端口也可以与其他技术和框架结合,如线程池、事件驱动等,从而实现更加强大和复杂的系统功能。 然而,使用IOCP完成端口和Socket封装的异步TCP类也存在一些局限性。比如对于初学者来说,可能需要一定的学习成本,需要掌握一定的操作和调试技巧。同时,如果应用不当,可能会导致系统资源的浪费和性能下降。因此,在使用这种技术时,需要开发者具有一定的经验和技术水平,可以充分发挥其优势,避免其劣势的影响。 总的来说,使用IOCP完成端口和Socket封装的异步TCP类是一种成熟的技术,它具有高效、灵活、可扩展等优势,能够满足大规模并发请求的处理需求,为系统的性能和可靠性提供了良好的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值