概述
IOCP 最简化说明
IOCP越说越复杂,我想尝试简明的从初学者的概念来说明,把最迷惑的部分简要说明:
关键点一:完全IO端口返回的消息,是系统保存在队列里的!不是直接给你返回!因为需要够快,所以建立完全端口后,完全端口自己会处理完所以连接、接收的动作,并把处理好的消息保存到队列里!它不管你需不需要,只要合法的都存好!所以我们关键的动作也就是要从队列去消息出来处理!
关键点二:它的关键函数:到队列去取数据的函数,它是阻塞式的。你执行了这个函数,如果队列里没有消息,它会停住等到有消息之后才往下走(当然也可以设置马上往下走,但实际我们都会让它等,这是它效率高的关键),所以大部分情况下,我们需要建立线程去执行这几个从队列里取数据的函数,让子线程等待直到队列里有新消息并每次取出一条进行处理!
对,这是关键点!
建立一个完全IO端口,最简单来说只要3步
1)Var WSData: TWSAData;
WSAStartup($0202, WSData); 初始化库,后面才能调用相关完全端口函数,WSData用于判断是否初始化成功
2)var FIocpHandle: THandle;
FIocpHandle:=CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); 这里创建了一个完全IO端口并返回其句柄
此时我们已经建立好完全IO端口了!
系统后台已经开始为我们处理数据队列。对于队列的处理,我们会用一个函数去等待看这个队列有没有新信息添加进来,
这个函数就是GetQueuedCompletionStatus,这个函数是阻塞的,它会停住直到等到有新消息进来!所以我们必须用线程来执行这个函数!!!!
这里就是完全IO端口的关键:你需要用一个或者多个线程执行GetQueuedCompletionStatus 以便尽快的取出消息并进行处理。
所以很多设计是会根据CPU的数量开尽可能多的线程来取消息!当然初学来说我们先开一个
3)GetQueuedCompletionStatus(CompletionPort, BytesTransferred,
ULONG_PTR(cSocket), POverlapped(PerIoData), INFINITE)
阻塞式的监听消息队列,第一个参数就是我们建立的完全IO端口,后面2个参数是返回消息的套接字信息,第三个是返回的数据,第四个参数是等待消息的时间,设置为INFINITE会一致等!
到目前为止,完全IO端口已经完全建立起来!!!!
但是,下面还有重要的地方需要处理。
目前我们服务器还没建立对连接的侦听!因为TCP的连接是需要其他步骤的。但你可以
把连接侦听看成不是完全IO端口的部分,这样会更容易理解。下面我们说连接侦听的部分,在这里,微软当然会用跟上面一样队列的方法来处理!
1) WSASocket(PF_INET, SOCK_STREAM, 0, nil, 0, WSA_FLAG_OVERLAPPED); 建立一个套接字
2)bind(FSocket, @Addr, SizeOf(Addr)) 把这个套接字跟端口(PORT)绑定,因为服务器基本都是固定一个端口的
3) listen(FSocket, MaxInt) 开始监听这个套接字
这三步后,服务器会开始处理所有的连接,我们不用管,系统处理好的连接也会放到队列里面!!!
对于队列,跟上面一样,我们最好是用线程是查看队列是不是有新的消息进来
这个查询连接队列的函数就是WSAAccept,这个查看队列消息的函数也是一个阻塞式的,所以我们又要用线程来执行它,等到连接队列有新消息进来后触发他往下走。
根据我初学者误区,我一直在找哪里触发连接、接收、断开的消息!不是的,真实的情况是我们需要建立线程来查询连接队列和接收消息队列!对,就是我们要处理的重点是怎么快速的从这两个队列里把消息取出来。并且需要再次强调,从这两个队列取数据的函数,它不会都是马上返回来的!如果没有新的消息,它是会停住以减少所有不需要的开销!所以建立线程来取是必须的。
好了,一个初学者理解到这,有错误理解的请改正我。后续继续学习看有没有错误!!
我用DELPHI写了一个最简单服务器的版本,也是从其他作者源码修改的,没有处理连接断开和把收到消息直接显示,完全是为了理解IOCP的最基本运作。
源码附上了DIOCP里列子的客户端作为测试。(后续附上源码)
最后
以上就是彪壮狗为你收集整理的IOCP 从初学者角度最简化的说明(delphi示例)的全部内容,希望文章能够帮你解决IOCP 从初学者角度最简化的说明(delphi示例)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复