動態

詳情 返回 返回

ping命令第1版主流程的源碼分析 - 動態 詳情

我們知道,ping 命令是通過 ICMP(Internet Control Message Protocol,互聯網控制消息協議)來檢測網絡連通性和延遲的。執行 ping 命令的主機(源主機)會向目標主機發送 ICMP Echo Request 報文,目標主機收到該報文後,應響應 ICMP Echo Reply 報文

如果源主機能夠收到目標主機返回的 ICMP Echo Reply 報文,就説明目標主機可達。再根據當前時間戳與發送時間戳(存儲在 ICMP 報文中)之間的差值,即可統計出網絡延遲。

下面來梳理一下 ping 第 1 版的主流程,看看 ICMP 報文的收發是如何實現的。

main(argc, char *argv[]) {
    // ①
    struct protoent *proto;
    proto = getprotobyname("icmp");
    s = socket(AF_INET, SOCK_RAW, proto->p_proto);

    // ②
    signal( SIGINT, finish );
    signal(SIGALRM, catcher);

    // ③
    catcher();    /* start things going */

    for (;;) {
        // ④
        int cc;
        cc=recvfrom(s, packet, ...);

        // ⑤
        pr_pack( packet, cc, ... );

        // ⑥
        if (npackets && nreceived >= npackets)
            finish();
    }
}

首先,創建 1 個 ICMP 協議的原始套接字raw sockets①。雖然使用普通套接字(也稱為 面向傳輸層的套接字)更方便,操作系統的內核會自動處理數據包的封裝與解析,我們完全不用關注 TCP/UDP、IP 等底層協議的格式,但同時也失去了修改網絡各層數據包的頭部和內容的機會。因此,必須使用原始套接字來收發 ICMP 報文。

接下來,分別註冊了用於處理信號 SIGINTSIGALRM 的函數②。當用户按下 Ctrl + C 時,信號 SIGINT 會觸發 finish() 函數執行。該函數會輸出如下彙總信息:


--- www.example.com PING statistics ---
5 packets transmitted, 5 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 9.674/10.968/11.726/0.748 ms

若未指定要發送的 ICMP 報文數量 npackets,ping 命令會不斷髮送 ICMP 報文,直到用户按下 Ctrl + C 才會執行 finish() 函數並退出。若指定了 npackets,則當收到的 ICMP 報文數量 nreceived 大於(須考慮沒有收到響應的情況)等於 npackets 時,則調用 finish() 函數並退出⑥。

而對於 SIGALRM 信號,只要定時器一到期(超時),該信號就會發出,並觸發 catcher() 函數的執行。

catcher() 函數③用於定時發送 ICMP Echo Request 報文。每發送完一個報文,再隨即通過 alarm(1) 設定定時器在 1 秒後產生 SIGALRM 信號,進而使 catcher() 函數自身在 1 秒後再被調用,以繼續發送下一個數據包,如此往復。

由於目標主機在收到 ICMP Echo Request 報文後,會向源主機返回 ICMP Echo Reply 報文,所以④這裏要通過 recvfrom() 接收。接收到的報文存儲在 packet 中,通過 pr_pack() ⑤函數格式化為如下字符串:

64 bytes from 93.184.216.34: icmp_seq=0 time=11.632 ms

以上就是 ping 命令的主流程。

另外,乍看之下,catcher() 函數和 recvfrom() 函數一發一收,要想實現反覆不斷收發似乎都應該寫到死循環 for (;;) { 中。但 catcher() 是通過定時器 SIGALRM 信號驅動的,每隔 1 秒執行 1 次,所以可以寫到死循環之外,這也就有點多線程或協程 go catcher(); 的風格了。

user avatar u_16640205 頭像 sovitjs 頭像 yujiaao 頭像 zero_dev 頭像 feibendemaojin 頭像 liudamao 頭像 tangzhangming 頭像 guangmingleiluodebaomihua 頭像 nizi_60e514d097c9a 頭像 junyidedalianmao 頭像 openbayescom 頭像 jkkang 頭像
點贊 20 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.