1. <wbr id="m8vu6"></wbr>

      <del id="m8vu6"><center id="m8vu6"><source id="m8vu6"></source></center></del>
        <p id="m8vu6"><sub id="m8vu6"></sub></p>

        VB.net 2010 視頻教程 VB.net 2010 視頻教程 VB.net 2010 視頻教程
        SQL Server 2008 視頻教程 c#入門經典教程 Visual Basic從門到精通視頻教程
        當前位置:
        首頁 > 硬件網絡 > 網絡工程師 >
        • 如何優雅地斷開TCP連接?

        • 2019-11-13 20:59 來源:未知

        socket關閉: close()和shutdown()的差異

        對于一個tcp連接,在c語言里一般有2種方法可以將其關閉:

        close(sock_fd);
        

        或者

        shutdown(sock_fd, ...);
        

        多數情況下這2個方法的效果沒有區別,可以互換使用。除了:

        • close() 是針對file的操作
        • shutdown() 是針對socket的操作

        nix系統里socket是1個文件,但文件不1定是1個socket;

        所以在進入系統調用后和達到協議層前(發出FIN包這一段), close()和shutdown()的行為會有1點差異。

        到達協議層以后,close()和shutdown()沒有區別。

        舉幾個栗子示范下close()和shutdown()的差異

        下面通過幾個例子演示下close()和shutdown()在多線程并發時的行為差異, 我們假設場景是:

        • sock_fd 是一個blocking mode的socket。
        • thread-1 正在對sock_fd進行阻塞的recv(),還沒有返回。
        • thread-2 直接對sock_fd調用close() 或 shutdown()。
        • 不考慮linger。

        栗子1: socket阻塞在recv()上, 調用close()

        
        
        1.  
          // Close a waiting recv()
        2.  
          Time
        3.  
          |
        4.  
          | thread-1 | thread-2 | tcpdump
        5.  
          | | |
        6.  
          | recv(sock_fd | |
        7.  
          | <unfinished ...> | |
        8.  
          1| | close(sock_fd) = 0 |
        9.  
          | | | // Some data arrived
        10.  
          | | | // after close()
        11.  
          2| | | < seq 1:36 ... length 35
        12.  
          | | | > ack 36 ...
        13.  
          | // Data was received. | |
        14.  
          3| <... recv resumed>) = 35 | |
        15.  
          4| | | > FIN sent
        16.  
          | | | < ack of FIN received
        17.  
          | | | ...
        18.  
          | // Can't be used any more | |
        19.  
          5v recv(sock_fd) = -1 | |

        在上面的例子里:

        • (1) thread-2 調用close()立即成功返回,這時recv()還在使用sock_fd

          這里因為有另外1個線程thread-1正在使用sock_fd, 所以只是標記這個sock_fd為要關閉的。 socket并沒有真正關閉。

          這時recv()還繼續處于阻塞讀取狀態。

        • (2) close()之后,有些數據到了,recv可以讀取并返回了。

        • (3) recv()收到數據, 正確退出。

        • (4) rece()結束調用,釋放socket的引用,這時底層開始關閉socket的流程。

        • (5) 再次調用recv()就會得到錯誤。

        可以看到,close()沒有立即關閉socket的連接,也沒有打斷等待的recv()。

        栗子2: socket阻塞在recv()上, 調用shutdown()

        
        
        1.  
          // Shutdown a waiting recv()
        2.  
          Time
        3.  
          |
        4.  
          | thread-1 | thread-2 | tcpdump
        5.  
          | | |
        6.  
          | recv(sock_fd | |
        7.  
          | <unfinished ...> | |
        8.  
          1| | shutdown(sock_fd) = 0 | > FIN sent
        9.  
          | | | < ack of FIN received
        10.  
          | | | ...
        11.  
          | // Woken up by shutdown() | |
        12.  
          | // no errno set | |
        13.  
          2| <... recv resumed>) = 0 | |
        14.  
          v | |

        在上面的例子里:

        • (1) thread-1還在等待sock_fd, thread-2調用shutdown(), 立即開始關閉socket的流程,發FIN 包等。

          然后, 內核中tcp_shutdown中會調用sock_def_wakeup 喚醒阻塞在recv()上的thread-1。

        • (2) 這時recv()阻塞的線程被喚醒等待并立即返回。 返回碼是0,表示socket已經關了。

        可以看到,shutdown()和close()不同, 會立即關閉socket的連接,并喚醒等待的recv()。

        以上2個例子的代碼

        close-or-shutdown-recv

        栗子3: socket阻塞在accept()上, 調用shutdown()

        類似的,對阻塞在accept()上的socket調用shutdown(),accept也會被喚醒:

        
        
        1.  
          // Shutdown a waiting accept()
        2.  
          Time
        3.  
          |
        4.  
          | thread-1 | thread-2
        免费看成年人视频大全_免费看成年人视频在线观看