網站首頁 編程語言 正文
一、PING簡介
PING(Packet Internet Grope),也稱因特網包探索器。PING使用ICMP回送(ECHO)請求和回送(ECHO)應答報文,一般用于測試網絡連通性,統計往返時間、丟包率等。PING UNIX命令格式如下:
ping [ - Rdfnqrv ] [ - c count ] [ - i wait ] [ - l preload ] [ - p pattern ] [ - s packetsize ] host
如果目標主機正在運行并連在網絡上,它就會對ICMP ECHO請求報文進行應答。每個ICMP ECHO請求報文包含一個IP和ICMP報文收不,后緊跟一個timeval結構,以及用來填充這個報文的填充字節。
缺省情況下,PING連續發送ICMP ECHO請求報文,直到收到中斷信號(Ctrl - C)。PING命令每秒發送一個報文,并且在程序結束是顯示一個簡要總結。PING命令在程序超時或接收到中斷信號時結束。host參數可以是有效的主機名或IP地址。
報文結構如下:
二、代碼實現? ? ? ??
# encoding:utf-8
import time
import struct
import socket
import select
def chesksum(data):
n = len(data)
m = n % 2
sum = 0
for i in range(0, n - m ,2):
sum += (data[i]) + ((data[i+1]) << 8)#傳入data以每兩個字節(十六進制)通過ord轉十進制,第一字節在低位,第二個字節在高位
if m:
sum += (data[-1])
#將高于16位與低16位相加
sum = (sum >> 16) + (sum & 0xffff)
sum += (sum >> 16) #如果還有高于16位,將繼續與低16位相加
answer = ~sum & 0xffff
# 主機字節序轉網絡字節序列(參考小端序轉大端序)
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def request_ping(data_type,data_code,data_checksum,data_ID,data_Sequence,payload_body):
# 把字節打包成二進制數據
icmp_packet = struct.pack('>BBHHH32s',data_type,data_code,data_checksum,data_ID,data_Sequence,payload_body)
icmp_chesksum = chesksum(icmp_packet) #獲取校驗和
# 把校驗和傳入,再次打包
icmp_packet = struct.pack('>BBHHH32s',data_type,data_code,icmp_chesksum,data_ID,data_Sequence,payload_body)
return icmp_packet
def raw_socket(dst_addr,icmp_packet):
'''
連接套接字,并將數據發送到套接字
'''
#實例化一個socket對象,ipv4,原套接字,分配協議端口
rawsocket = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.getprotobyname("icmp"))
#記錄當前請求時間
send_request_ping_time = time.time()
#發送數據到網絡
rawsocket.sendto(icmp_packet,(dst_addr,80))
#返回數據
return send_request_ping_time,rawsocket,dst_addr
def reply_ping(send_request_ping_time,rawsocket,data_Sequence,timeout = 2):
while True:
#開始時間
started_select = time.time()
#實例化select對象,可讀rawsocket,可寫為空,可執行為空,超時時間
what_ready = select.select([rawsocket], [], [], timeout)
#等待時間
wait_for_time = (time.time() - started_select)
#沒有返回可讀的內容,判斷超時
if what_ready[0] == []: # Timeout
return -1
#記錄接收時間
time_received = time.time()
#設置接收的包的字節為1024
received_packet, addr = rawsocket.recvfrom(1024)
#獲取接收包的icmp頭
#print(icmpHeader)
icmpHeader = received_packet[20:28]
#反轉編碼
type, code, checksum, packet_id, sequence = struct.unpack(
">BBHHH", icmpHeader
)
if type == 0 and sequence == data_Sequence:
return time_received - send_request_ping_time
#數據包的超時時間判斷
timeout = timeout - wait_for_time
if timeout <= 0:
return -1
def dealtime(dst_addr,sumtime,shorttime,longtime,accept,i,time):
sumtime += time
print(sumtime)
if i == 4:
print("{0}的Ping統計信息:".format(dst_addr))
print("數據包:已發送={0},接收={1},丟失={2}({3}%丟失),\n往返行程的估計時間(以毫秒為單位):\n\t最短={4}ms,最長={5}ms,平均={6}ms".format(i+1,accept,i+1-accept,(i+1-accept)/(i+1)*100,shorttime,longtime,sumtime))
def ping(host):
send, accept, lost = 0, 0, 0
sumtime, shorttime, longtime, avgtime = 0, 1000, 0, 0
#TODO icmp數據包的構建
data_type = 8 # ICMP Echo Request
data_code = 0 # must be zero
data_checksum = 0 # "...with value 0 substituted for this field..."
data_ID = 0 #Identifier
data_Sequence = 1 #Sequence number
payload_body = b'abcdefghijklmnopqrstuvwabcdefghi' #data
# 將主機名轉ipv4地址格式,返回以ipv4地址格式的字符串,如果主機名稱是ipv4地址,則它將保持不變
dst_addr = socket.gethostbyname(host)
print("正在 Ping {0} [{1}] 具有 32 字節的數據:".format(host,dst_addr))
for i in range(0,4):
send = i + 1
#請求ping數據包的二進制轉換
icmp_packet = request_ping(data_type,data_code,data_checksum,data_ID,data_Sequence + i,payload_body)
#連接套接字,并將數據發送到套接字
send_request_ping_time,rawsocket,addr = raw_socket(dst_addr,icmp_packet)
#數據包傳輸時間
times = reply_ping(send_request_ping_time,rawsocket,data_Sequence + i)
if times > 0:
print("來自 {0} 的回復: 字節=32 時間={1}ms".format(addr,int(times*1000)))
accept += 1
return_time = int(times * 1000)
sumtime += return_time
if return_time > longtime:
longtime = return_time
if return_time < shorttime:
shorttime = return_time
time.sleep(0.7)
else:
lost += 1
print("請求超時。")
if send == 4:
print("{0}的Ping統計信息:".format(dst_addr))
print("\t數據包:已發送={0},接收={1},丟失={2}({3}%丟失),\n往返行程的估計時間(以毫秒為單位):\n\t最短={4}ms,最長={5}ms,平均={6}ms".format(
i + 1, accept, i + 1 - accept, (i + 1 - accept) / (i + 1) * 100, shorttime, longtime, sumtime/send))
if __name__ == "__main__":
i = input("請輸入要ping的主機或域名\n")
ping(i)
三、結果顯示
D:\Miniconda3\python.exe D:/網絡協議分析與設計/實驗/ping/ping.py
請輸入要ping的主機或域名
www.baidu.com
正在 Ping www.baidu.com [14.215.177.39] 具有 32 字節的數據:
來自 14.215.177.39 的回復: 字節=32 時間=34ms
來自 14.215.177.39 的回復: 字節=32 時間=26ms
來自 14.215.177.39 的回復: 字節=32 時間=32ms
來自 14.215.177.39 的回復: 字節=32 時間=28ms
14.215.177.39的Ping統計信息:
?? ?數據包:已發送=4,接收=4,丟失=0(0.0%丟失),
往返行程的估計時間(以毫秒為單位):
?? ?最短=26ms,最長=34ms,平均=30.0ms
?
Process finished with exit code 0
原文鏈接:https://blog.csdn.net/Small_Teenager/article/details/122123299
相關推薦
- 2022-10-15 詳解C語言中雙指針算法的使用_C 語言
- 2021-12-09 數據庫建表設計六范式介紹_數據庫其它
- 2022-08-20 Python超細致探究面向對象_python
- 2022-04-07 c++中的volatile和variant關鍵字詳解_C 語言
- 2022-05-10 thymeleaf跳轉到響應頁面(modelandview 中的view)
- 2022-08-21 C語言數據結構之單鏈表的實現_C 語言
- 2024-01-13 LocalDate、LocalDateTime與timestamp、Date的轉換
- 2022-12-28 PyQt5學習之QThread類的使用詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支