小時候不太會玩電腦,一般自己玩的時候流程是:開始--附加功能--游戲與娛樂。
倘若旁邊有妹子在圍觀柴底,我便會win+R-----cmd----ping baidu.com.然后看著屏幕上跳出一行行數(shù)字蚯撩,假裝自己看得懂的樣子,過一會兒再慢悠悠地打開太空彈球玩起來
現(xiàn)在想起來真的是圖樣圖森破咽弦,甚至還非常naive啊徒蟆。
這個ping程序算是我對計算機最早的認識了,作為一個生活在圖形界面時代的人類型型,這也是我第一次知道了命令行形式的人機交互段审。
之前學(xué)習了計算機網(wǎng)絡(luò)的知識,知道了它的原理其實是利用ICMP協(xié)議的回顯請求來實現(xiàn)的闹蒜,通過構(gòu)造ICMP報文向目的主機發(fā)出寺枉,然后接收返回報文,計算經(jīng)過的時間绷落,就能計算出主機到目的主機之間的RTT(Round Trip Time)姥闪,也就是我們平時講的延遲。
由于ICMP工作在網(wǎng)絡(luò)層,不能保證交付砌烁,也不保證順序筐喳,所以發(fā)送多個請求的時候,可能會出現(xiàn)亂序的情況函喉,于是ping程序中在數(shù)據(jù)段保存包本身的發(fā)送時間避归,接收到之后用系統(tǒng)時間減去報文中讀取的時間即可得到RTT。為了簡化過程函似,我在此只發(fā)送一個報文槐脏。
要構(gòu)造ICMP包,首先要知道其格式撇寞,
Type (8bit) | Code(8bit) | Checksum (16bit) | Identifier (16bit) | Sequence Number (16bit) | Data ...
我么要用到的是回顯請求顿天,對應(yīng)type是8堂氯,code是0,checksum要通過特定的算法獲得牌废,其他部分自己處理即可咽白。
import socket
import array,struct,time,select
def checksum(data):
if(len(data)%2!=0):
data+=b'\x00'
a=array.array('H',data)
s=0
for d in a:
s=s+d
s=(~s)&0xffff
return s
這段代碼將已經(jīng)除checksum以外其它打包好的數(shù)據(jù)進行一系列計算,得到一個16bit的數(shù)鸟缕,用于差錯檢測晶框,如果計算錯誤,服務(wù)器方不會響應(yīng)懂从,你也就接受不到響應(yīng)的報文了授段。在編寫網(wǎng)絡(luò)程序的時候,調(diào)試時要利用抓包工具查看自己發(fā)出的報文的具體內(nèi)容番甩,否則難以得知自己錯在何處侵贵。
def send_packet(my_socket,destination_addr):
header=struct.pack('bbHh',8,0,1,1)
data=0
data=struct.pack('d',data)
checks=checksum(header+data)
packet=struct.pack('bbHHh',8,0,checks,1,1)+data
my_socket.sendto(packet,(destination_addr,1))
t=recive_ping(my_socket, 5)
print(t)
def recive_ping(my_socket,timeout):
timeleft=timeout
while True:
starttime=time.time()
select_=select.select([my_socket],[],[],timeleft)
if select_[0]==[]:
print("timeout")
return -1
t=time.time()-starttime
return t
這兩個函數(shù)一起完成了報文的構(gòu)造和發(fā)送,這其中用到了raw類型socket缘薛,select用于接收數(shù)據(jù)窍育,由于數(shù)據(jù)要翻譯成二進制發(fā)送,直接連接字符串肯定是不行的宴胧,所以要用struct將數(shù)據(jù)打包漱抓。
def do(addr):
icmp=socket.getprotobyname('icmp')
s=socket.socket(socket.AF_INET,socket.SOCK_RAW,icmp)
send_packet(s, addr)
do("220.181.57.217")
這就是程序的入口了,運行效果就不貼了恕齐,反正就是打印出一個浮點數(shù)乞娄。數(shù)字的含義是延遲時間(實際是rtt)。
與ping相似的另一個traceroute显歧,實現(xiàn)原理也類似补胚,它利用的是ip頭部的TTL,通過構(gòu)造指向目的主機的ttl從1遞增的數(shù)據(jù)包,就能獲得源主機到目的主機之間所有經(jīng)過的路由追迟,這可以在網(wǎng)上找到不少資料溶其,此處不再贅述。