基于ICMP协议的ping程序实现
来源:互联网 发布:软件测试工程师学习 编辑:程序博客网 时间:2024/05/16 18:36
ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。 要利用ICMP协议实现ping功能的程序,Ping程序将采取下列步骤:
(1)创建类型为SOCK_RAW的一个套接字,同时设定协议类型为IPPROTO_ICMP。
(2)创建并初始化ICMP头。
(3)调用sendto,将ICMP请求发送给远程主机。
(4)调用recvfrom,以接受任何ICMP响应。
#!/usr/bin/python# -*- coding:UTF-8 -*-#导入相关包import os,socket,struct,select,time #struct包用于处理二进制数据,selcet包监听是否有可读、可写或异常事件产生ICMP_ECHO_REQUEST = 8 # ICMP报文类型DEFAULT_TIMEOUT = 2 # 默认超时时间DEFAULT_COUNT = 4 # 默认发送报文的数量class Pinger(object): #定义Pinger类 #定义初始化方法 def __init__(self, target_host, count=DEFAULT_COUNT,timeout=DEFAULT_TIMEOUT): self.target_host = target_host self.count = count self.timeout = timeout def do_checksum(self, source_string): #计算校验和 sum = 0 max_count = (len(source_string)/2)*2 # 取小于等于len(source_string)最大偶数 count = 0 while count < max_count: #ord返回单字符的ASCII码 val = ord(source_string[count + 1])*256 + ord(source_string[count]) sum = sum + val #累加到sum sum = sum & 0xffffffff #sum取后32位 count = count + 2 if max_count<len(source_string): #若len(source_string)为奇数,加上source_string的最后一位 sum = sum + ord(source_string[len(source_string) - 1]) sum = sum & 0xffffffff sum = (sum >> 16) + (sum & 0xffff) #将sum的高16位加上低16位 sum = sum + (sum >> 16) #将sum加上sum的高16位 answer = ~sum #将sum取反 answer = answer & 0xffff # 取answer的低16位 answer = answer >> 8 | (answer << 8 & 0xff00) # 将answer右移8位与上answer左移8位 return answer # 返回计算得到的校验和 def send_ping(self, sock, ID): #发送ICMP报文 target_addr = socket.gethostbyname(self.target_host) # 获得目的 ip 地址 my_checksum = 0 # 初始化校验和为0 # 将数据按“bbHHh“ 格式打包 b:integer 1B H:unsigned short 2B h:short 2B header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0,my_checksum, ID, 1) bytes_In_double = struct.calcsize("d") # 得到 ’d’ 格式的数据字节数 data = (100 - bytes_In_double) * "Q" #data 一共 100 字节 发送一些列 ’Q...’ data = struct.pack("d", time.time()) + data # data 前加上时间 # 根据header和data计算校验和 my_checksum = self.do_checksum(header + data) header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1) # 打包header 并将校验和由主机字节顺序转为网络字节顺序 packet = header + data # 将header和data组合成packet sock.sendto(packet, (target_addr, 1)) # 向目标地址发送packet def receive_ping(self, sock, ID, timeout): #接收服务器返回的报文 time_remaining = timeout # 设置超时时间 while True: start_time = time.time() readable = select.select([sock], [], [], time_remaining) # 监听sock是否有数据可读 time_spent = (time.time() - start_time) if readable[0] == []: # 没有可读数据 return time_received = time.time() # 记录接收的时间 recv_packet, addr = sock.recvfrom(1024) # 接收1024个字节数据 icmp_header = recv_packet[20:28] # 前20字节为IP首部 icmp首部一共8个字节 ‘bbHHh’ 1+1+2+2+2=8 type, code, checksum, packet_ID, sequence = struct.unpack("bbHHh", icmp_header) # 从 icmp_header 中解包 if packet_ID == ID: # ID匹配 bytes_In_double = struct.calcsize("d") time_sent = struct.unpack("d", recv_packet[28:28 +bytes_In_double])[0] # 从 data 中得到发送的时间 return time_received - time_sent # 返回所用的时间 time_remaining = time_remaining - time_spent if time_remaining <= 0: # 超时返回 return def ping_once(self): #Ping一次服务器,返回延迟时间 icmp = socket.getprotobyname("icmp") # 得到协议号 try: # 创建原始套接字 m_sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp) except socket.error, (errno, msg): if errno == 1: # 没有权限 msg += "ICMP messages can only be sent from root user processes" print msg else: print errno except Exception, e: print "Exception: %s" %(e) my_ID = os.getpid() & 0xFFFF # 进程id self.send_ping(m_sock, my_ID) # 发送报文 delay = self.receive_ping(m_sock, my_ID, self.timeout) # 接收回应 m_sock.close() return delay def ping(self): #实现Ping count for i in xrange(self.count): print "Ping to %s..." % self.target_host, try: delay = self.ping_once() # 返回延迟时间 except socket.error, e: print "Ping failed. (socket error: '%s')" % e[1] break if delay == None: print "Ping failed. (timeout within %ssec.)" % self.timeout else: delay = delay * 1000 print "Get pong in %0.4fms" % delayif __name__ == '__main__': #Main函数 target_host='www.runoob.com' # 目标主机 pinger = Pinger(target_host=target_host) #创建Ping对象 pinger.ping() # 调用ping方法
需要特别注意的是在Linux操作系统下,会出现下图这种情况!!!
Operation not permittedICMP messages can only be sent from root user processes
现在加上sudo后就可以ping通了!运行结果如下:
阅读全文
0 0
- 基于ICMP协议的ping程序实现
- ICMP 协议及 Ping程序的实现
- ICMP协议及ping程序的实现
- ICMP协议的PING程序
- ping程序及ICMP协议程序的实现
- 基于ICMP的一个ping程序
- java实现ICMP协议的ping功能
- ICMP协议之ping实现
- ICMP协议之ping实现
- ICMP协议之ping实现
- ICMP协议之ping实现
- ICMP协议之ping实现
- ICMP协议之ping实现
- Linux网络编程---ICMP协议分析及ping程序实现
- ICMP 的 Ping 实现
- 基于icmp的ping函数
- ICMP协议Ping方法的Python实现解析
- TCP/IP协议-ICMP和 ping 程序
- C语言结构体数组
- kafka数据可靠性深度解读
- 决定开始写博客
- springmvc json 响应http406解决
- WCF 消息推送
- 基于ICMP协议的ping程序实现
- vnc 连接linux centos 7 系统的桌面
- 判断String空值的效率排行
- NSDI'17-论文阅读[CherryPick:Adaptively Unearthing the Best Cloud Configurations for Big Data Analytics]
- 快速玩转大数据_顺利渡过34岁裁退危机
- PHP异步的玩法
- Linux统计|监控工具--SAR
- Android TabLayout setCustomView 实现带图标的tab
- canvas