freeeyes 发表于 2010-12-28 10:11:03

关于Proactor模式下短发的疑问

短读和短发在公网应用中很常见,在Reactor下很好理解,在Proactor模式下,短读也很好理解,但是短写似乎有些问题。
诚然,一般情况下,你会把要发送的数据放入系统队列,通过:
m_Writer.write(*pmblk, pmblk->length()
实现把要发送的数据包存入一个系统队列。
这时候,如果发送完成,系统会回调:
handle_write_stream(const ACE_Asynch_Write_Stream::Result &result)
在这里一般的写法是,
if(result.success())
{
    //判断是否出现短写,如果出现短写,将数据重新写入。
    ......
    //处理其他错误,如果是致命的,则断开链接。
    ......
}
这时候,我以为这样对短写的判定会导致数据包乱序,尤其在数据频繁传送的时候。昨天晚上查阅了一下<TCP系统编程2>中的一些资料,异步模式下,当数据发送不完整的情况会报错,这时候,异步系统不会等待回调事件处理结束,而会技术发送下一个数据包,这时候就算你调用了
//短写,继续发送
result.message_block ().rd_ptr (result.bytes_transferred ());
if (m_Writer.write (result.message_block (), stLost) == -1)
我个人感觉也是没用的,因为这个数据包会排列在队列中,并不会排列在发送失败后的数据包的位置,而是在队列的尾部,造成客户端接受的数据包乱序。所以我个人认为,在异步系统中,短写的处理是有问题的。
不知道这样的理解是否有问题。

nono436 发表于 2010-12-28 10:38:16

楼主,我想问问怎么用多反应器增加连接建立效率?
http://www.acejoy.com/bbs/viewthread.php?tid=1572&highlight=reactor
就像你这里说的那样,怎么使用多个反应器?
我发现我建立3000个连接很慢,速度越来越慢,我想主要是单线程接受连接,但怎么样可以增加速度

freeeyes 发表于 2010-12-28 10:46:17

你先确认是不是反应器的问题,建议你把反应器处理时间打印出来,我建立5000个链接的时候,发现大部分是new和delete造成的系统慢,而不是反应器。比如创建一个handler要处理很多初始化代码,而这些代码很大的情况下是重复建设的,注销反应器,接受数据包也最好做缓冲池。

nono436 发表于 2010-12-28 11:21:35

比如我想测试3000个连接,测试代码怎么写,是不是启动20个线程,每个线程建立100个连接,这样合适吗?

modern 发表于 2010-12-29 11:50:32

本帖最后由 modern 于 2010-12-29 11:52 编辑

就这个问题,昨天下午和freeeyes各自精读msdn的相关章节。最后比较一致的观点是:
由于IOCP并没有就GetQueuedCompletionStatus的短写短读问题提供进一步说明。
但是可以肯定的是IOCP的GetQueuedCompletionStatus函数实际内部会调用重叠IO的函数。
而MSDN对于WSAGetOverlappedResult的说明比较明确。
GetQueuedCompletionStatus只有成功完成(completed successfully)才会返回读到的数据长度。
而对于其他各种情况比如重叠IO未完成(主要就是这句话),
或者完成出错,未确定状态,参数问题等,lpcbTransfer均将不会被更新,

对此我的理解是重叠IO一定会返回一个完成态或者失败,
而不会将中间的半完成态返回,因此无须处理短写短读问题。

最后的结论是对于短读的问题,代码保留如果触发做日志特殊标记。
而对于短写的问题,由于确实在逻辑上会出现乱序的问题,这解释不通。
万恶的GetQueuedCompletionStatus在完成之后会将overlaped数据结构
从IOCP的队列中dequeue出去,如果完成队列里仍然有该连接的待发数据包,
则必乱序,这时即使重新投递异步的write(WSASEND)也解决不了这个逻辑问题。
因此只能打印日志,暂不作进一步处理。

对此欢迎大家讨论,拍砖。

下面是原文:
If WSAGetOverlappedResult succeeds, the return value is TRUE. This means that the overlapped operation has completed successfully and that the value pointed to by lpcbTransfer has been updated. If WSAGetOverlappedResult returns FALSE, this means that either the overlapped operation has not completed, the overlapped operation completed but with errors, or the overlapped operation's completion status could not be determined due to errors in one or more parameters to WSAGetOverlappedResult. On failure, the value pointed to by lpcbTransfer will not be updated. Use WSAGetLastError to determine the cause of the failure (either of WSAGetOverlappedResult or of the associated overlapped operation).
页: [1]
查看完整版本: 关于Proactor模式下短发的疑问