wishel 发表于 2008-8-5 22:45:08

异步读写的两个奇怪问题

参考ace(5.6)自带的example/Reactor/Proactor/test_proactor.cpp

1.ACE_Asynch_Acceptor<Handler>,在接受新连接之后会从对方socket预读一个message blok(大小512),然后在调用Handler的open()的时候把这个message block作为参数传递过去。此时该Handler要先把这一部分数据处理了,然后继续下面的动作(一般是继续读),不然的话就会丢失数据。例子中是通过自己做了一个fake的result来处理的。
2.ACE_Asynch_Write_Stream在对socket进行write的时候,最后一次write完成后(complete),不要立即退出程序。否则接收方会因为对方连接断掉,无法读到数据,报错: (ACE_Asynch_Read_Stream::read: 指定的网络名不再可用。)一般当处理的数据较多(文件较大)时容易产生这样的错误。这时可在最后一次write完成后,在handle_write_stream退出前,sleep一到几秒钟。等接收方收完在退出。
该例子中因为同时有ACE_Asynch_Transmit_File,所以没有这样的情况。但是如果把有关ACE_Asynch_Transmit_File的内容屏蔽掉,就可以看到这个问题。把Sender::handle_write_stream()中最后一段,this->stream_write_done_ = 1;之后加一句ACE_OS::sleep(1); 问题解决。

wishel 发表于 2008-9-12 10:23:59

发现这个帖子里有问题1的详细解释:
http://acejoy.com/bbs/viewthread.php?tid=821&extra=page%3D1

对ACE的这个open的实现感到不解,为何缺省时要抛出附带数据?这样很难让用户理解
按道理应该是缺省时不抛,但可以由用户自定义选择是否抛和抛出大小。

winston 发表于 2008-9-12 11:12:12

我的理解就是OS的约束关系和一些设计考虑。
如果改成你想要的设计,想一下如下情景:
客户要求预读4K的数据,而且读取完成后返回。但是对端只返回了1K,剩下的就不发了,一直在那里耗着等待。
这样,你就无法对系统的网络连接处理器对象做什么事情了。因为连open方法都调不出来,只好干等,相当于死在那里了。这种设计是很不安全而且被动的。
相反,当前的这种实现,把决定权交给了使用者。如果收回的信息数量不足,需要时候,他至多再发一次预读即可。如果有人恶意连接,你可以进行测试和超时,进行防范。
以上是我的理解。

wishel 发表于 2008-9-12 15:51:53

我的疑惑主要是为什么要默认预读?
一般情况是客户先connect,然后send。服务器先accept,然后recv。
而预读时,服务器在accept的时候,在recv之前,进行了部分预读。这好像不大符合常规习惯。
其实可以完全不用预读,accept只做接受和建立连接,读数据只用recv来实现。如果recv收到的字节数不足,再重新发起recv就可以了,直到最后收到足够的数据。

winston 发表于 2008-9-13 07:46:23

参见Windows网络编程,第六章 - Scalable Winsock Applications,第一节 - APIs and Scalability
预读能提高性能。

wishel 发表于 2008-9-17 17:25:26

呵呵,明白了,原来是为了性能的考虑。
页: [1]
查看完整版本: 异步读写的两个奇怪问题