请教IOCP投递问题,此问题很是奇怪

mrsupersky 2012-10-03 09:37:53
RT 此问题很是奇怪的很。
看了很久IOCP的文章了。
但是对于投递操作,网络上似乎分为两大派系,
下面我分别说一下:

第一种投递方式:
是在IOCP线程池 外部直接调用WSASend或者WSARecive?而PostQueuedCompletionStatus只是被用来需要停止IOCP工作线程的时候调用一下(我自己,感觉这个函数是不是被用得鸡肋了?)
然后再在IOCP 工作线程里面通过
调用GetQueuedCompletionStatus 得到结果的状态通知。

第二种投递方式:
在IOCP工作线程外部只调用 PostQueuedCompletionStatus 来进行任何投递操作。

然后再调用 GetQueuedCompletionStatus 得到Post的投递,然后判断投递的类型,比如是Send数据,
那就调用WSASend来发送一下。。。
而发送的成功与否的结果通知还是通过GetQueuedCompletionStatus这个在下一次的时候得到?



那么,这两种方法,到底哪一种是正确的方法呢?肯定只有一种是正确的而且最合理额吧?
————问题分割线—————————————————————————————问题分割线————
还有 IOCP 比如 我要发送 一个2KB的数据,是不是只要在外部投递一次就好了?

这里的外部投递是指在IOCP工作线程之外,进行一个PostQueuedCompletionStatus 函数的调用。

然后在工作线程里面 是不是受到投递请求只要调用一次WSASend,一次性发送然后等待结果就行了?但是我缓冲区只设置了1kB。。。这个要怎么弄,自己处理发送两次吗?

————问题分割线—————————————————————————————问题分割线————
于此同时,我还发现另外一个问题。
很多人写IOCP都是一个个投递,这样是不是一种错误的做法?

IOCP的N次投递(重叠投递),一次处理,不就是IOCP的最大的好处吗,
如果不重叠了,IOCP就不能够将多个操作合并为一个,而这就会失去IOCP很大的IO并发处理的意义,是这样的吧?
...全文
467 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiayadong 2012-12-19
  • 打赏
  • 举报
回复
数据投递只有WSA开头的几个异步函数可以投递数据,是可以在线程之外的任何时候进行投递操作的,且可以进行多次数据投递操作,但要注意,如果投递数据包过多,但在GetQueuedCompletionStatus中暂时又没有返回,则可能会耗尽内存(投递一个数据包,系统会锁定一个内存页面,记得是4K一页),导致异常,所以一般都进行比较简单的一应一答式的数据投递;或投递0大小的请求,有数据需要接收时,再申请真正的数据投递请求。
xumaojun 2012-12-16
  • 打赏
  • 举报
回复
不好意思,我前面没有看清楚你问的意思,仔细看了一下,发现确实第一种是对的,我也用过第一种方式.
mrsupersky 2012-12-15
  • 打赏
  • 举报
回复
引用 7 楼 xumaojun 的回复:
两种都可以,根据实际需要,如果服务器是被动的接收一条数据发送一个应答可以使用第二中方式,如果需要在不同地方主动发送一些数据可以用第一种方式,IOCP好像没有限制投递IO操作的限制。


又被你说晕了。我都快否定第二种了。
xumaojun 2012-12-15
  • 打赏
  • 举报
回复
两种都可以,根据实际需要,如果服务器是被动的接收一条数据发送一个应答可以使用第二中方式,如果需要在不同地方主动发送一些数据可以用第一种方式,IOCP好像没有限制投递IO操作的限制。
mrsupersky 2012-12-15
  • 打赏
  • 举报
回复
谢谢各位的回答,基本有思路了,虽然到底是不是这样,官方也没有说得很清楚....
「已注销」 2012-10-11
  • 打赏
  • 举报
回复
为了简单期间,每个连接,建议WSASEND和WSARECV都每次投递一个,等返回数据了再投递下一个
Eleven 2012-10-08
  • 打赏
  • 举报
回复
一般都是第一种
「已注销」 2012-10-08
  • 打赏
  • 举报
回复
主楼说的第二种投递根本是开玩笑,根本没理解IOCP是什么东西。
后两个问题,我想,还是等你搞清楚IOCP是个什么东西再说吧。

实际上,不要把IOCP想复杂了,从概念上说,他是个很简单的东西。

IOCP是个什么东西呢?

比方说,我要进行一个I/O操作,如send(sock, buff, 100, 0); // 使用sock发送buff开始的100个字节。

我要是这么直接调用,就是同步操作,就是说,在此函数返回后,此操作也就完成了,并且,此函数将执行的结论返回给我(是不是正确以及操作了多少字节)。

那么,我可以将这个“操作”交给IOCP机制去做,就是让IOCP去做这件事(这个操作)。那么,我可以用标准的Windows写函数WriteFile将这个操作交给IOCP。 Windows内部肯定在sock句柄上做了标记,如果标记为绑定IOCP的I/O句柄,则不进行同步操作,而是作为一个“操作”,将此“操作”交给IOCP的输入队列。IOCP的处理线程将此操作从输入队列里取出,然后在IOCP的线程里进行操作,操作结束将结果以“完成包”的结构放入输出队列,则用户可以用Get-status函数将完成包取出来。(至于IOCP如何在“恰当的时机”里进行实际操作,是Windows的内部问题,此处无需关注。)



bsnry 2012-10-03
  • 打赏
  • 举报
回复
PostCompletionStatus这个函数 似乎不是用来投递的,是告知 iocp所管理的线程要结束

投递函数:

WSARecv

WSASend

WriteFile

ReadFile

目前记得的就有这4个

project2502 2012-10-03
  • 打赏
  • 举报
回复
CreateIoCompletionPort() 与一个socket对象绑定

NtSetInformationFile() 绑定一个fileobject到io完成端口

///////////////////////////////

对这个fileobject进行的操作( 比如wsaSend() )
变为Io request packet 在内核传递到AFD驱动
再传递到NDIS驱动 以NET_BUFFER形式 在NDIS中传递到网卡驱动

网卡小端口驱动完成发送
ndis根据发送结果调用IoCompleteRequest()完成Irp

IoComoleteRequest()发现这个Irp的文件对象关联着一个完成端口
这个Irp被挂入了Kqueue的 链表中 当做是完成了

操作的结果石沉大海

//////////////////////////////////////////////////

GetQueuedCompletionStatus() 等于是调用这个函数的线程被加入了完成端口的线程池

NtRemoveIoCompletion()

KeRemoeQueue()
这个函数从kqueue对象的Irp队列中取出一个Irp 释放 并通过函数的输入参数返回irp对应的操作的结果
//////////////////////////////////

对线程进行限制是kqueue对象的工作

如果kqueue中没有Irp 那么 所有的GetQueuedCompletionStatus()线程都会被阻塞
直到有一个Irp到来 即直到有一个线程调用wsasend 之类的函数 并被网卡驱动完成


////////////////////////////////////

而PostQueuedCompletionStatus()调用NtSetIocompletion()

它制造了一个Irp挂入队列 让阻塞着的GetQueuedCompletionStatus()函数返回

//////////////////////////////////

写了一些原理看看是不是对你能有帮助

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧