ping功能的原理解析和原始碼實現

2021-10-10 20:39:51 字數 3065 閱讀 1122

三、總結

ping命令的工作原理:向網路上的另乙個主機系統傳送icmp報文,如果指定系統得到了報文,它將把報文一模一樣地傳回給傳送者,這有點象潛水艇聲納系統中使用的發聲裝置

這裡就得說下icmp報文的格式,我們需要自己手動組乙個icmp的包發給主機進行探測

型別(8位)

編碼(8位)

校驗和(16位)

識別符號順序號

可選資料

icmp主要分為差錯報文和詢問報文,資料格式如上表所示。差錯報文提供一組易懂的出錯報告資訊,以快速診斷出出錯原因。詢問報文分為請求回顯(ping請求)、回顯應答(ping應答)、位址掩碼請求、位址掩碼應答等等。我們這裡主要是測試主機可答性,實現ping功能,主要介紹下詢問報文的格式組包:

1. icmp報文的前4個位元組是統一的格式,共有三個字段:即型別,**和檢驗和。

2. 8位型別和8位**字段一起決定了icmp報文的型別。

型別8,**0:表示回顯請求(ping請求)

型別0,**0:表示回顯應答(ping應答)

3. 16位的檢驗和字段:包括資料在內的整個icmp資料報的檢驗和;其計算方法和ip頭部檢驗和的計算方法一樣的。

4. 識別符號和順序號:icmp報文中的識別符號和序列號字段由傳送端任意選擇設定,這些值在應答中將被返回,這樣,傳送端就可以把應答與請求進行匹配。

下面顯示組包**

struct icmp *picmp;

/* 型別和**分別為icmp_echo,0代表請求回送 */

picmp->icmp_type = icmp_echo;

picmp->icmp_code =0;

picmp->icmp_cksum =0;

//校驗和

picmp->icmp_seq =1;

//序號

picmp->icmp_id =

getpid()

;//取程序號作為標誌

ptime =

(struct timeval *

)picmp->icmp_data;

gettimeofday

(ptime,

null);

//資料段存放傳送時間

picmp->icmp_cksum =

compute_cksum

(picmp)

;

icmp報文傳輸在ip層,所以主機需要通過在網路層進行連線和報文的傳送,另外ping操作可以直接對網域名稱進行操作,如果下發的是網域名稱在連線之前還要先對網域名稱進行ip的轉換。

操作**如下:

struct hostent * phost =

null

;// 儲存主機資訊

struct sockaddr_in dest_addr;

// ipv4專用socket位址,儲存目的位址

in_addr_t inaddr;

socket

(pf_inet, sock_raw, ipproto_icmp));

dest_addr.sin_family = af_inet;

/* 將點分十進位制ip位址轉換為網路位元組序 */if(

(inaddr =

inet_addr

(ipaddr)

)== inaddr_none)

memmove

(&dest_addr.sin_addr, phost->h_addr_list[0]

, phost->h_length);}

else

picmp =

(struct icmp*

)sendbuffer;

sendto

(sock_icmp, sendbuffer, icmp_len,0,

(struct sockaddr *

)dest_addr,

sizeof

(struct sockaddr_in));

// 報文傳送

當主機能收到報文時,說明目的主機可達,驗證返回報文中的識別符號和自己之前發出去的是否一致,來判斷當次傳輸是否正常。由於我們這裡只是為了模擬ping功能,實現源主機到目的主機的可達性,就沒有去解析一些ping的時間等

流程如下:

int

recvepacket

(int sock_icmp,

struct sockaddr_in *dest_addr)

;struct timeval select_timeout;

fd_set rset;

select_timeout.tv_sec =7;

select_timeout.tv_usec =0;

fd_zero

(&rset)

;fd_set

(sock_icmp,

&rset);if

(select

(sock_icmp+1,

&rset,

null

,null

,&select_timeout)

<=0)

if((recvbytes =

recvfrom

(sock_icmp, recvbuffer, recv_buffer_size,0,

(struct sockaddr *

)dest_addr,

&addrlen)

)<0)

gettimeofday

(&recvtime,

null);

if(unpack

(&recvtime,recvbuffer)==-

1)return recvbytes;

}int

unpack

(struct timeval *recvtime,

char

*recvbuffer)

else

return-1

;}

本文主要通過原始碼實現了ping功能,可以用來檢測一些主機的可達性,可以直接在應用層上使用。如果後續有ping測試的時間上的需求,可以自己再去對時間進行計算。

C STL PJ 原始碼 list 原理解析

了解 c list 是屬於雙向迴圈鍊錶,就是 雙向鍊錶 與 迴圈鍊錶 的結合體。所以我們必須對 雙向鍊錶 與 迴圈鍊錶 了解必要的知識。下篇我們就解析 c list容器的奧秘吧!雙向鍊錶 1.雙向鍊錶的結構 表示的鍊錶的 前驅 prev 儲存位址 表示的鍊錶儲存的 值的部分 value 表示的鍊錶的...

C STL PJ 原始碼 list 原理解析2

1.什麼是雙向迴圈列表?雙向鍊錶是對與 迴圈鍊錶 與 雙向鍊錶 的結合 注意 如果對 迴圈鍊錶 與 雙向鍊錶 不太熟識去看之前的文章!這裡對鍊錶不做過多解析!2.鍊錶的架構!prev 前驅 value 值 next 後繼指標 3.直接上 這裡不會對 萃取 進行分析,所以我把 萃取 去掉。本章節對原始...

SpringMVC原理 解析請求引數(原始碼分析)

在使用springmvc的時候,我們經常編寫controller層的介面,並使用一些註解傳遞一些引數,那麼這些引數是怎麼封裝進我們的請求的呢?springmvc是怎麼解析這些引數的呢?本文主要通過原始碼分析springmvc解析請求引數的全過程。編寫乙個controller類,裡面寫上乙個介面方法 ...