Posted on 2010-11-20 23:07
S.l.e!ep.¢% 閱讀(770)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
epoll
我原先的client端代碼流程如下:??
創(chuàng)建一個(gè)socket
設(shè)為異步socket(fcntl)
將socket加入epoll
connect到遠(yuǎn)端(此時(shí)connect調(diào)用返回非0,但errno為EINPROGRESS,表示正在建立連接中)
epoll_wait之
捕獲到EPOLLOUT事件,此時(shí)便認(rèn)為connect已經(jīng)成功,client端開始發(fā)消息
這個(gè)過程通常能夠運(yùn)轉(zhuǎn),但是線上環(huán)境復(fù)雜多變,如果發(fā)生這種情況:server進(jìn)程調(diào)用listen開始偵聽后,被gdb或信號(hào)掛住了,此時(shí)異步connect會(huì)怎樣?很遺憾,client端的epoll_wait依然返回EPOLLOUT,甚至往此socket里發(fā)消息都返回成功,只有當(dāng)發(fā)的消息多得占完了server端的tcp緩沖以后(窗口收縮到很小),send調(diào)用才開始失敗。這時(shí)候用 losf -i 看網(wǎng)絡(luò)連接也很有趣,client端的機(jī)器顯示連接建立了,server端的卻顯示沒有這個(gè)連接。
仔細(xì)想想,OS這樣做是正確的,畢竟connect的語義只是“連接”,當(dāng)server掛住時(shí),連接還是能成功的,但你能不能往里面發(fā)消息那就是另外一回事了。
所以對(duì)于應(yīng)用來說,異步socket想要知道connect后連接是不是可以正常收發(fā)數(shù)據(jù)了,還是要靠應(yīng)用層的一問一答才能知道。
====== 2010.5.14 ======
昨天同事朱照遠(yuǎn)給了一個(gè)更正確的解決方案,可參考之:
“收到EPOLLOUT也不能認(rèn)為是TCP層次上connect(2)已經(jīng)成功,要調(diào)用getsockopt看SOL_SOCKET的SO_ERROR是否為0。若為0,才表明真正的TCP層次上connect成功。至于應(yīng)用層次的server是否收/發(fā)數(shù)據(jù),那是另一回事了。”