陳碩 (giantchen_AT_gmail)
Blog.csdn.net/Solstice
今天收到一位網友來信:
在 simple 中的 daytime 示例中,服務端主動關閉時調用的是如下函數序列,這不是隻是關閉了連接配接上的寫操作嗎,怎麼是關閉了整個連接配接?
陳碩答複如下:
Muduo TcpConnection 沒有提供 close,而隻提供 shutdown ,這麼做是為了收發資料的完整性。
TCP 是一個全雙工協定,同一個檔案描述符既可讀又可寫, shutdownWrite() 關閉了“寫”方向的連接配接,保留了“讀”方向,這稱為 TCP half-close。如果直接 close(socket_fd),那麼 socket_fd 就不能讀或寫了。
用 shutdown 而不用 close 的效果是,如果對方已經發送了資料,這些資料還“在路上”,那麼 muduo 不會漏收這些資料。換句話說,muduo 在 TCP 這一層面解決了“當你打算關閉網絡連接配接的時候,如何得知對方有沒有發了一些資料而你還沒有收到?”這一問題。當然,這個問題也可以在上面的協定層解決,雙方商量好不再互發資料,就可以直接斷開連接配接。
等于說 muduo 把“主動關閉連接配接”這件事情分成兩步來做,如果要主動關閉連接配接,它會先關本地“寫”端,等對方關閉之後,再關本地“讀”端。練習:閱讀代碼,回答“如果被動關閉連接配接,muduo 的行為如何?” 提示:muduo 在 read() 傳回 0 的時候會回調 connection callback,這樣客戶代碼就知道對方斷開連接配接了。
Muduo 這種關閉連接配接的方式對對方也有要求,那就是對方 read() 到 0 位元組之後會主動關閉連接配接(無論 shutdownWrite() 還是 close()),一般的網絡程式都會這樣,不是什麼問題。當然,這麼做有一個潛在的安全漏洞,萬一對方故意不不關,那麼 muduo 的連接配接就一直半開着,消耗系統資源。
完整的流程是:我們發完了資料,于是 shutdownWrite,發送 TCP FIN 分節,對方會讀到 0 位元組,然後對方通常會關閉連接配接,這樣 muduo 會讀到 0 位元組,然後 muduo 關閉連接配接。(思考題:在 shutdown() 之後,muduo 回調 connection callback 的時間間隔大約是一個 round-trip time,為什麼?)
另外,如果有必要,對方可以在 read() 傳回 0 之後繼續發送資料,這是直接利用了 half-close TCP 連接配接。muduo 會收到這些資料,通過 message callback 通知客戶代碼。
那麼 muduo 什麼時候真正 close socket 呢?在 TcpConnection 對象析構的時候。TcpConnection 持有一個 Socket 對象,Socket 是一個 RAII handler,它的析構函數會 close(sockfd_)。這樣,如果發生 TcpConnection 對象洩漏,那麼我們從 /proc/pid/fd/ 就能找到沒有關閉的檔案描述符,便于查錯。
muduo 在 read() 傳回 0 的時候會回調 connection callback,然後把 TcpConnection 的引用計數減一,如果 TcpConnection 的引用計數降到零,它就會析構了。
參考:
《TCP/IP 詳解》第一卷第 18.5 節,TCP Half-Close。
《UNIX 網絡程式設計》第一卷第三版第 6.6 節, shutdown() 函數。
本文轉自 陳碩 部落格園部落格,原文連結:http://www.cnblogs.com/Solstice/archive/2011/02/25/1965342.html,如需轉載請自行聯系原作者