iocp代码实例

文章介绍了IOCp(完成端口)的概念,它是服务器处理大量并发连接的理想模型。通过对比阻塞IO、非阻塞IO、select和wsaEventSelect,解释了IOCp如何实现系统级别的并行处理,允许服务器同时处理多个数据。文章以简洁的语言和实例代码展示了如何创建和使用IOCp,包括监听、读写操作,并强调了使用指针存储客户对象以避免析构问题的关键点。
摘要由CSDN通过智能技术生成

---------
能帮到你的话,就给个赞吧 😘
********
hello大家好,今天向大家介绍iocp代码。放心不会很难,这篇文章将在100字以内结束。同时有什么疑问尽管提问,github也行,保证回答。
要清楚iocp代码就要分两部分,一部分是iocp,一部分是代码。
iocp很简单,它是服务器的理想模型,也就是我们最容易想的/直观的模型。
我们期望一个服务器能够服务无限多个客户,即任意多个客户来了服务器都能处理。但这种直观的感觉计算机是做不到的,或者说是通过多个步骤而来。

因为很简单,上述的事情其实是涉及两个操作一个是监听,一个是响应,而我们一次只能执行一个,要么监听要么响应。不过这个好解决,开个线程即可。但这种方法很多缺点,怎么说呢,其实是因为它一般在课程开头,不符合这个段位。后来呢,非阻塞io,select,wsaEventSelect,这几个一步一步来,解决一个一个问题。

监听,读,写这仨都是io。以往呢我们一个io就阻塞了,为啥呢,因为没数据io就卡那了,一直在那等数据,所以啊,程序卡不怪你cpu,而是没数据了,io阻塞了,然后有数据再把数据io完结束。非阻塞io就是没数据io就结束了,不多bb,有数据就io完结束。那非阻塞我们就可以遍历多个io判断有没有数据。但是这样很卡,因为io是系统调用,应用调一次就很浪费,不行。然后有了select,select就做了个优化,应用层只调一次io,但这一次把io都传给系统,然后系统再调用n次io。有观众就会问了,这不是耍猴吗,你在逗我,非也非也,遛狗遛狗。之前那个非阻塞io是n+n,因为你要先在应用层调一次,在系统层再调一次,而这个呢是应用层总共调1次,系统n次,还是进步了。到这里,都是通过调io来判断有无数据,我们急需一种不调io也能判数据的方法,最好有数据来通知应用就行,也就是wsaEventSelect。这个已经很好的实现有数据来通知就行,但是呢它是由事件来实现的,而这个事件系统有限制,系统最多只能监听64个,太少了,而且通知仅是系统告诉应用有数据,还没io到应用,应用还需要再调一次io。也就是说最理想的有数据来通知我,应该是有数据系统直接io给我,然后再通知我,应用仅负责处理数据,然后不限数量。这个是想当然的,但也是最理想的,即iocp。总结一下 有数据时直接给到应用并通知,不限数量。也就是我们想当然的应用能随时处理多个数据。这种叫并行,同时处理多个。怎么实现呢,异步。之前系统限制只有64个,现在系统可以有n多个异步,做到真正的n多个并行。而且系统仅需要一个异步id区分不同异步即可,非常简单。做到n多个并行了,就剩通知了。有的同学就会问了,你这io咋回事呢,不还没讲咋给到应用吗,非常简单,因为上述的异步就是io,我们把io操作给异步了,叫做异步io。也就是说系统本身就有异步调用的方式,我们异步调用io就行了,完成时系统通知,数据也就到了。我真的是无语,你有这么好的调用方式为啥不早说,别问,问就是不知道,因为大家都是按这个顺序来讲的,我也不好意思破规矩,我是觉得这异步调用真香,直接讲不就行了,前面的都是废话。那么我们就创建n多个io,直接丢给系统就行,反正是系统返回。注意,监听是io,所以服务器都是先丢多个监听,等系统返回处理监听即可,这就是iocp。真的是iocp,因为这个系统就是iocp。那有的朋友就发现了,这感觉不对啊,服务器不都是监听请求,处理请求吗,你这咋还主动创建。没错,这就是iocp最大的不同,服务器不用监听,主动出击,等iocp返回。

接下来就要开始讲流程及代码设计了。放心也没啥难的,很随意的。以服务器一个recv send关闭为例。

首先创建一个iocp。

然后就是绑定。客户(client)要绑定,服务端(server)也要绑定。需要将两个参数绑到iocp。1个是自身的套接字,另一个是相关的数据结构也就是绑自己。因为异步io完成通知时不返回套接字,返回的是这个数据结构,那个套接字仅仅是iocp用作区分而已,所以你可以理解为就是要把这个数据结构绑到iocp上。也就是绑自己。一开始没客户,所以绑服务,一个样。

绑完就投io就行了,然后就等通知,然后处理数据。那server不需要读写,只投监听io。至于数量嘛,随便投,反正并行系统管。

然后就是等通知处理数据。也没啥。

不过不要以为就是先处理监听,再处理读写。这个等通知处理数据是另开的线程,数据分三种,监听,读,写,是处理这三种数据的,只不过一开始投的只有监听io。

怎么处理呢,都很简单,只不过监听io格式比较固定。

监听io到了就说明客户端连接了,就创建客户,绑定iocp,投通信流程所需的io就行,在这里就是投一个读,然后再投一个监听,因为这个监听io不是已经结束了,所以再投一个。先投客户还是服务端的都行,无所谓。

处理读写更简单了。因为iocp已经直接将数据给到应用了,所以就该怎么处理就怎么处理。因为我们是一个recv一个send嘛,那处理完读就投一个send,处理完send投一个关闭。关闭怎么投呢,因为recv/send数据为0是关闭信号,我们就可以投一个没有数据的读写io。不过这俩还有点区别,投读io呢就是等对面关闭,投send就是自己直接关闭了。那还不如直接关闭了。

流程就这么简单,接下来要讲一些代码设计。其实大部分都很随意,但有些是根据api设计的。

比如io的内容就是根据不同调用所需参数设计,像读写io用的参数一摸一样,但监听多一个套接字,所以写成两个类。而且线程处理的时候还要区分是读是写所以CLIENT_IO还需要一个标志位。这样的话SOCKET_HANDLE就必须存基类指针了。

其他的设计就很随意了,我是把所有的变量/资源都放在主线程中了,所以工作线程都用主线程传的地址。

值得注意的就是存所有客户的vector<SOCKET_HANDLE*> clients,这个vector必须存指针,不能存对象,因为client是要跟iocp绑定的,而vector扩容缩容都会将原先的对象析构,所以不能存对象。

还有一个就是根据ol找io地址,这个不需要ol放在io首位。在注释中有。

线程参数就是工作线程需要什么都往里面写就行了。至于为什么WOKERTHREADPARA的成员都是引用,那是因为本来不是引用的,都是对象,然后只用一个线程参数所有工作线程都用其即可,但是后来添了个threadId,现在线程退出时输出各自id,这就不行了,因为前面几个一样,但threadId各自不一,又不想浪费空间所以就用指针/引用,但是之前是按对象调的嘛,所以就引用了。

应该齐全了,有待补充的后续再写吧。

但我有个疑问,就是在参考连接中退出线程中说到需要用一个事件,但我没想明白这个事件作用在哪,还请赐教。

本文项目地址:GitHub - diandengpao/iocp

参考:完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三_完成端口模型的优缺点_PiggyXP的博客-CSDN博客

配套项目:GitHub - sly461/IOCPModel: 服务器icop模型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值