程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> muduo 的 shutdown()沒有直接關閉 TCP連接的原因

muduo 的 shutdown()沒有直接關閉 TCP連接的原因

編輯:關於C++

今天收到一位網友來信:

在 simple 中的 daytime 示例中,服務端主動關閉時調用的是如 下函數序列,這不是只是關閉了連接上的寫操作嗎,怎麼是關閉了整個連接?

1: void DaytimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn)

2: {

3:   if (conn->connected())

4:   {

5:     conn->send(Timestamp::now().toFormattedString() + "\n");

6:     conn->shutdown();

7:   }

8: }

9:

10: void TcpConnection::shutdown()

11: {

12:   if (state_ == kConnected)

13:   {

14:     setState(kDisconnecting);

15:     loop_->runInLoop(boost::bind(&TcpConnection::shutdownInLoop, this));

16:   }

17: }

18:

19: void TcpConnection::shutdownInLoop ()

20: {

21:   loop_->assertInLoopThread();

22:   if (! channel_->isWriting())

23:   {

24:     // we are not writing

25:     socket_->shutdownWrite();

26:   }

27: }

28:

29: void Socket::shutdownWrite()

30: {

31:   sockets::shutdownWrite(sockfd_);

32: }

33:

34: void sockets::shutdownWrite (int sockfd)

35: {

36:   if (::shutdown(sockfd, SHUT_WR) < 0)

37:   {

38:     LOG_SYSERR << "sockets::shutdownWrite";

39:   }

40: }

陳碩答復如下:

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 的引用計數降到零,它就會析構了。

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved