做一个服务端程序,采用IOCP模型,现在有几个问题不是太清楚请教高人

Joininthefun 2008-07-13 10:36:35
我最近做一个服务端程序(一个服务端对应多个客户端,客户端连接后发送消息后等待服务端处理完成后下发,客户端收到数据后断开连接,需要查询时再连接),采用IOCP模型,现在有几个问题不是太清楚请教一下:

1. 我的一个套接字上如果已经投递了一个读操作,这时我在投递一个写操作可不可以,看网上的一些答案说不可以,我理解是我们投递的读写操作应该只是发到IOCP的队列中,不应该有影响吧!


2. 看到网上说可用对一个套接字维持应挂起的操作(读或写)不太明白怎么做,这样做的目的是什么,

3. 如果我的读写操作被挂起(客户端在我的写时侯突然正常关闭或非正常关闭),我怎么结束被挂起的读写操作,有人说用PostQueuedCompletionStatus()函数,但是我不明白怎么用, 如果用户是正常关闭我的服务端能感知到吗,如何知道? get函数中的状态是我投递操作是带下去的,客户端的

多谢!



...全文
178 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
Joininthefun 2008-07-23
  • 打赏
  • 举报
回复
多谢大家回复!也许是我想多了,来结贴了!
WinEggDrop 2008-07-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 Joininthefun 的回复:]
首先感谢大家回答!:)

我投递的时候肯定是用不同的缓冲区,

关于第二个问题我昨天也想了一下,估计那篇帖子的作者是想说在上面维持一个读操作(就是说当一个套接字上的读操作完成后再投递一个读操作,这样如果套接字上没用数据一直会在等待在队列中,一但有数据过来就马上能知道,我的理解),其实我的第二个问题是想知道如果我的投递一个读操作已经返回了,但是数据不一定通过AFD.sys发送出去了,如果在发送一半是客户端已经断开了…
[/Quote]

你主要只是检测发送后最终返回的结果,如果你得到的是完全发送成功的信号,那就是发送成功了.至于你所担心的事情,例如系统发送一半客户端就断开了,这些是异常事件,而且都是系统内核在处理的,你的程序也根本没办法知道.再退一万步说,如果客户端断开了,你还担心那些数据有没有发送成功呢?
如果你连这些也要担心,那要担心的事情还多着,例如有些防火墙就会过滤一些数据不让通过的,难道你连这些也要检测数据有没有被防火墙过滤掉没被发送到远程?
僵哥 2008-07-15
  • 打赏
  • 举报
回复
[Quote=引用楼主 Joininthefun 的帖子:]
1. 我的一个套接字上如果已经投递了一个读操作,这时我在投递一个写操作可不可以,看网上的一些答案说不可以,我理解是我们投递的读写操作应该只是发到IOCP的队列中,不应该有影响吧!


2. 看到网上说可用对一个套接字维持应挂起的操作(读或写)不太明白怎么做,这样做的目的是什么,

3. 如果我的读写操作被挂起(客户端在我的写时侯突然正常关闭或非正常关闭),我怎么结束被挂起的读写操作,有人说用PostQueuedCompletionStatus()函数,但是我不明白怎么用, 如果用户是正常关闭我的服务端能感知到吗,如何知道? get函数中的状态是我投递操作是带下去的,客户端的[/Quote]
1.Overlapped就是为了让用户可以发出请求即不用理会其过程的一种机制。你不仅仅可以投递一个写操作,甚至可以投递多个写操作,只是需要控制整个系统当中未决(未完成)的操作数量即可,当然,最好的办法还是针对一个连接仅存一个未决的发送和一个未决的接收即可。服务器不要考虑单连接上的性能,而应该考虑的是整体,并且是整体的的平衡。

2.这里说的“挂起的操作”应该是指的未决即未完成的操作,正如1当中我的所建议的。

3.读写操作未完成,是不可以通过PostQueuedCompletionStatus来结束的,PostQueuedCompletionStauts,只能令阻塞在GetQueuedCompletionStatus函数当中的线程得到一个影响事件,从而可以进行一些决策,包括退出等。要使得这些未决的操作完成,只须将其关联的Socket关闭即可。通常情况下对于完成端口,只要客户端产生异常断开等情况,都会得到响应,仅仅只是时间长短的关系。完成端口与epoll不同在于,完成端口的内部线程池是有在做读写操作的,于时它可以发现连接的状态,而epoll是响应事件的,没有预读尝试,于是当对端异常断开之后无法被发现。

[Quote=引用 6 楼 Joininthefun 的回复:]
关于第二个问题我昨天也想了一下,估计那篇帖子的作者是想说在上面维持一个读操作(就是说当一个套接字上的读操作完成后再投递一个读操作,这样如果套接字上没用数据一直会在等待在队列中,一但有数据过来就马上能知道,我的理解),其实我的第二个问题是想知道如果我的投递一个读操作已经返回了,但是数据不一定通过AFD.sys发送出去了,如果在发送一半是客户端已经断开了,这时我需要怎么处理?
[/Quote]
我估计,你这里所写的读操作应该想说的是一个写操作。

对于完成端口能不能保证WSASend提交的数据在返回完成通知的时候已经将数据发送出去,这个一直是一个比较具争议性的话题,理由很简单,在实际测试过程当中没有谁碰到过不能完全发送出去的情况,这是一个实实在在的“现象”,但是Microsoft自己给出的Demo(参见Microsoft Platform SDK),却进行了进一步的判断,这就使得众人对这个问题疑惑不已。

虽然实测过程当中,存在这种情况仅仅只有客户端产生异常(GetQueuedCompletion返回是不成功的,但是TransferBytes是大于0的)时才出现类似的问题,但是我个人建议,并且我个人也是在WSASend返回成功通知之后做出进一步判断。这个判断确实是一个不小的消耗,但是为了保障服务程序的正常与稳定,却又不得不去花费。虽然也在一些应用当中对此仅仅只是使用一个assert,但至今未发现有任何异常记录。最终还是把希望寄托给Microsoft,在将来的某一个版本的MSDN当中给一个正面的答案或建议。
cppwin 2008-07-15
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 Joininthefun 的回复:]
如果我的投递一个读操作已经返回了,但是数据不一定通过AFD.sys发送出去了,如果在发送一半是客户端已经断开了,这时我需要怎么处理?
[/Quote]

读操作不会发送出去数据.

afd.sys是内核驱动,无需深究它的具体机制.

你只需要在收到完成通知时,知道这个操作是否成功.
没有"半成功"或"半失败"的概念.

假设你一次发送100字节,但内核只发了40字节,就给你一个完成通知,
对你来说,就是 发送40字节 这个操作 成功了. 下一步你再发送剩余的60字节.
Joininthefun 2008-07-15
  • 打赏
  • 举报
回复
自己顶
Joininthefun 2008-07-14
  • 打赏
  • 举报
回复
首先感谢大家回答!:)

我投递的时候肯定是用不同的缓冲区,

关于第二个问题我昨天也想了一下,估计那篇帖子的作者是想说在上面维持一个读操作(就是说当一个套接字上的读操作完成后再投递一个读操作,这样如果套接字上没用数据一直会在等待在队列中,一但有数据过来就马上能知道,我的理解),其实我的第二个问题是想知道如果我的投递一个读操作已经返回了,但是数据不一定通过AFD.sys发送出去了,如果在发送一半是客户端已经断开了,这时我需要怎么处理?

scq2099yt 2008-07-14
  • 打赏
  • 举报
回复
up
cppwin 2008-07-14
  • 打赏
  • 举报
回复
1.可以同时投递写操作.
2.看不明白
3.有些连接断开是无法获得通知的,你需要采用心跳检测的办法.
yyunffu 2008-07-14
  • 打赏
  • 举报
回复
学习!
yebeans 2008-07-14
  • 打赏
  • 举报
回复
补充:
1.投递发送和接受时,用不同的WSAOVERLAPPED应该没有问题(可以在结构体中添加相应标志)。
2.我也没看懂该怎么断句。。。
WinEggDrop 2008-07-14
  • 打赏
  • 举报
回复
[Quote=引用楼主 Joininthefun 的帖子:]
我最近做一个服务端程序(一个服务端对应多个客户端,客户端连接后发送消息后等待服务端处理完成后下发,客户端收到数据后断开连接,需要查询时再连接),采用IOCP模型,现在有几个问题不是太清楚请教一下:

1. 我的一个套接字上如果已经投递了一个读操作,这时我在投递一个写操作可不可以,看网上的一些答案说不可以,我理解是我们投递的读写操作应该只是发到IOCP的队列中,不应该有影响吧!


2. 看到网上说可用对一个套接字维持应挂…
[/Quote]

1.如果你读和写投递用的是同一个buff,自然是不行.先不考虑buff被锁定问题的解决,先说最简单.如果buff中原来没数据,你投递写那是根本不合逻辑(有数据才向外发送吧);如果有buff,例如buff是4K大小,已经有4K数据在buff中,buff都满了,你投递读和写,如果读操作先被执行了,你难道要将原来buff的数据复盖掉?

2."一个套接字维持应挂起的操作"
不清楚是你写错了,还是那书笔误,从来是没听说过"应挂起的操作"这样的名词,估计是从英文翻译过来的,但没翻译好.

3."如果我的读写操作被挂起(客户端在我的写时侯突然正常关闭或非正常关闭),我怎么结束被挂起的读写操作."
如果在写时客户端关掉socket,那么你的WSASend()本身就会返回错误,根本不需要你再做什么操作,根据返回错误就能判断是什么回事.如果在投递了读时,客户端关闭socket的话,那么IOCP工作线程中的GetQueuedCompletionStatus()会返回错误的.根据错误你也能判断是什么回事.
以上只是在正常关闭时的判断.还有在一些情况下客户端不正常关闭情况下,你的程序可能接收不到任何信号可以判断客户的socket是断开了,这时侯就需要某种机制去判断.一般服务程序都会通过一定机制去检测连接着的客户端是否还在线,例如定时发送心跳包,或定时检查和客户端多长时间没有数据通讯了(具体可以查看ftp服务器,代理服务器等,客户一般在一定时间内没发送数据到服务端,就会被服务器断开)

18,356

社区成员

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

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