ICMP协议Ping方法的Python实现解析

2023-11-18

ICMP协议Ping方法的Python实现解析

说明

流程

  1. 选择目标网址
  2. 解析对方ip地址
  3. 构造数据报,添加校验和,发送并记录发送时间
  4. 循环监听,直到接收到数据报,提取对方发送时间,获得数据报传输时间;若超时则返回None

细节解析

检查管理员权限

if ctypes.windll.shell32.IsUserAnAdmin() == 0:
    print 'Sorry! You should run this with administrative privileges.'
    sys.exit()

获取本机IP

my_ID = os.getpid() & 0xFFFF

构造Socket

icmp = socket.getprotobyname('icmp')
my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)

构造数据报

data = (192 - byte_in_double) * "P"
data = struct.pack("d", time.clock()) + data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1)
packet = header + data

计算校验和

checksum = 0
count = (len(source) / 2) * 2
i = 0
while i < count:
    temp = ord(source[i + 1]) * 256 + ord(source[i]) # 256 = 2^8
    checksum = checksum + temp
    checksum = checksum & 0xffffffff # 4,294,967,296 (2^32)
    i = i + 2

if i < len(source):
    checksum = checksum + ord(source[len(source) - 1])
    checksum = checksum & 0xffffffff

# 32-bit to 16-bit
checksum = (checksum >> 16) + (checksum & 0xffff)
checksum = checksum + (checksum >> 16)
answer = ~checksum
answer = answer & 0xffff

# why? ans[9:16 1:8]
answer = answer >> 8 | (answer << 8 & 0xff00)

关于校验和最后为何要进行首尾调换,参考RFC文档:http://www.faqs.org/rfcs/rfc1071.html

提取信息,计算发送时长

time_received = time.clock()
# socket.recvfrom(bufsize[, flags])
# The return value is a pair (string, address)
rec_packet, addr = my_socket.recvfrom(1024)
icmp_header = rec_packet[20 : 28]
ip_type, code, checksum, packet_ID, sequence = struct.unpack("bbHHh", icmp_header)
if ip_type != 8 and packet_ID == ID: # ip_type should be 0
    byte_in_double = struct.calcsize("d")
    time_sent = struct.unpack("d", rec_packet[28 : 28 + byte_in_double])[0]
    return time_received - time_sent

源代码

GitHub:https://github.com/kemingy/Network/tree/master/ICMP

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: Moming
# 2016-04-07
# ping for Windows

import os
import sys
import socket
import struct
import select
import time
import ctypes

ICMP_ECHO_REQUEST = 8

def receive_ping(my_socket, ID, timeout):
    """
    receive the ping from the socket
    """
    start_time = timeout
    while True:
        start_select = time.clock()
        # select.select(rlist, wlist, xlist[, timeout])
        # wait until ready for read / write / exceptional condition
        # The return value is a triple of lists
        what_ready = select.select([my_socket], [], [], start_time)
        how_long = (time.clock() - start_select)
        if what_ready[0] == []: #timeout
            return

        time_received = time.clock()
        # socket.recvfrom(bufsize[, flags])
        # The return value is a pair (string, address)
        rec_packet, addr = my_socket.recvfrom(1024)
        icmp_header = rec_packet[20 : 28]
        ip_type, code, checksum, packet_ID, sequence = struct.unpack("bbHHh", icmp_header)
        if ip_type != 8 and packet_ID == ID: # ip_type should be 0
            byte_in_double = struct.calcsize("d")
            time_sent = struct.unpack("d", rec_packet[28 : 28 + byte_in_double])[0]
            return time_received - time_sent

        start_time = start_time - how_long
        if start_time <= 0:
            return


def get_checksum(source):
    """
    return the checksum of source
    the sum of 16-bit binary one's complement
    """
    checksum = 0
    count = (len(source) / 2) * 2
    i = 0
    while i < count:
        temp = ord(source[i + 1]) * 256 + ord(source[i]) # 256 = 2^8
        checksum = checksum + temp
        checksum = checksum & 0xffffffff # 4,294,967,296 (2^32)
        i = i + 2

    if i < len(source):
        checksum = checksum + ord(source[len(source) - 1])
        checksum = checksum & 0xffffffff

    # 32-bit to 16-bit
    checksum = (checksum >> 16) + (checksum & 0xffff)
    checksum = checksum + (checksum >> 16)
    answer = ~checksum
    answer = answer & 0xffff

    # why? ans[9:16 1:8]
    answer = answer >> 8 | (answer << 8 & 0xff00)
    return answer


def send_ping(my_socket, ip_addr, ID):
    """
    send ping to the given ip address
    """
    ip = socket.gethostbyname(ip_addr)

    # Header is type (8), code (8), checksum (16), id (16), sequence (16)
    my_checksum = 0

    # Make a dummy heder with a 0 checksum
    # struct.pack(fmt, v1, v2, ...)
    # Return a string containing the values v1, v2, ... packed
    # according to the given format.
    # b:signed char, h:short 2, H:unsigned short 2
    header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
    # struct.calcsize(fmt)
    # Return the size of the struct corresponding to the given format.
    byte_in_double = struct.calcsize("d") # C type: double
    data = (192 - byte_in_double) * "P" # any char is OK, any length is OK
    data = struct.pack("d", time.clock()) + data

    # Calculate the checksum on the data and the dummy header.
    my_checksum = get_checksum(header + data)

    # It's just easier to make up a new header than to stuff it into the dummy.
    # socket.htons(x)
    # Convert 16-bit positive integers from host to network byte order.
    header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1)
    packet = header + data
    # my_socket.sendto(packet, (ip, 1)) # getsockaddrarg() takes exactly 2 arguments
    my_socket.sendto(packet, (ip, 80)) # it seems that 0~65535 is OK (port?)


def ping_once(ip_addr, timeout):
    """
    return either delay (in second) or none on timeout.
    """
    # Translate an Internet protocol name to a constant suitable for
    # passing as the (optional) third argument to the socket() function.
    # This is usually only needed for sockets opened in “raw” mode.
    icmp = socket.getprotobyname('icmp')
    try:
        # socket.socket([family[, type[, proto]]])
        # Create a new socket using the given address family(default: AF_INET),
        # socket type(SOCK_STREAM) and protocol number(zero or may be omitted).
        my_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
    except socket.error:
        raise

    # Return the current process id.
    # int: 0xFFFF = -1, unsigned int: 65535
    my_ID = os.getpid() & 0xFFFF

    send_ping(my_socket, ip_addr, my_ID)
    delay = receive_ping(my_socket, my_ID, timeout)

    my_socket.close()
    return delay


def icmp_ping(ip_addr, timeout = 2, count = 4):
    """
    send ping to ip_addr for count times with the given timeout
    """
    for i in range(count):
        print 'ping ' + cmd,
        try:
            delay = ping_once(ip_addr, timeout)
        except socket.gaierror, e:
            print "failed. (socket error: '%s')" % e[1]
            break

        if delay == None:
            print 'failed. (timeout within %s second.)' % timeout
        else:
            print 'get reply in %0.4f ms' % (delay * 1000)


# main
if __name__ == '__main__':
    if ctypes.windll.shell32.IsUserAnAdmin() == 0:
        print 'Sorry! You should run this with administrative privileges.'
        sys.exit()

    while True:
        try:
            cmd = raw_input('Please input the ip address you want to ping: ')
            if cmd == '':
                break
            icmp_ping(cmd)
        except EOFError:
                break
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ICMP协议Ping方法的Python实现解析 的相关文章

  • 递归 lambda 表达式可能吗?

    我正在尝试编写一个调用自身的 lambda 表达式 但我似乎找不到任何语法 或者即使它是可能的 本质上我想将以下函数传输到以下 lambda 表达式中 我意识到这是一个愚蠢的应用程序 它只是添加 但我正在探索可以在 python 中使用 l
  • 在 Windows cmd 中,如何在不引用完整路径的情况下运行当前目录中的可执行文件(而不是 %PATH% 中同名的可执行文件)? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在尝试运行可执行文件foobar来自目录 但 Windows 也恰好有一个名为的可执行文件 或命令 foobar 在 UNIX 中 我
  • Pandas:GroupBy 到 DataFrame

    参考这个关于 groupby 到 dataframe 的非常流行的问题 https stackoverflow com questions 10373660 converting a pandas groupby object to dat
  • 如何检查python xlrd库中的excel文件是否有效

    有什么办法与xlrd库来检查您使用的文件是否是有效的 Excel 文件 我知道还有其他库可以检查文件头 我可以使用文件扩展名检查 但为了多平台性我想知道是否有任何我可以使用的功能xlrd库本身在尝试打开文件时可能会返回类似 false 的内
  • 删除 Django 1.7 中的应用程序(和关联的数据库表)

    是否可以使用 Django 1 7 迁移来完全删除 卸载应用程序及其所有跟踪 主要是其所有数据库表 如果没有 在 Django 1 7 中执行此操作的适当方法是什么 python manage py migrate
  • sklearn 中的 pca.inverse_transform

    将我的数据拟合后 X 我的数据 pca PCA n components 1 pca fit X X pca pca fit transform X 现在 X pca 具有一维 当我根据定义执行逆变换时 它不是应该返回原始数据 即 X 二维
  • 没有名为 StringIO 的模块

    我有Python 3 6 我想从另一个名为 run py 的 python 文件执行名为 operation py 的 python 文件 In operation py I do from cStringIO import StringI
  • Keras:如何保存模型或权重?

    如果这个问题看起来很简单 我很抱歉 但是阅读 Keras 保存和恢复帮助页面 https www tensorflow org beta tutorials keras save and restore models https www t
  • Gspread如何复制sheet

    在 Stackoverflow 上进行谷歌搜索和搜索后 我想我找不到有关如何复制现有工作表 现有模板工作表 并将其保存到另一个工作表中的指南 根据文档 有重复表 https gspread readthedocs io en latest
  • SMTP_SSL SSLError: [SSL: UNKNOWN_PROTOCOL] 未知协议 (_ssl.c:590)

    此问题与 smtplib 的 SMTP SSL 连接有关 当与 SMTP 无 ssl 连接时 它正在工作 在 SMTP SSL 中尝试相同的主机和端口时 出现错误 该错误仅基于主机 gmail 设置也工作正常 请检查下面的示例 如果 Out
  • Matplotlib 中 x 轴标签的频率和旋转

    我在下面编写了一个简单的脚本来使用 matplotlib 生成图形 我想将 x tick 频率从每月增加到每周并轮换标签 我不知道从哪里开始 x 轴频率 我的旋转线产生错误 TypeError set xticks got an unexp
  • Python:IndexError:修改代码后列表索引超出范围

    我的代码应该提供以下格式的输出 我尝试修改代码 但我破坏了它 import pandas as pd from bs4 import BeautifulSoup as bs from selenium import webdriver im
  • Mac OSX 10.6 上的 Python mysqldb 不工作

    我正在使用 Python 2 7 并尝试让 Django 项目在 MySQL 后端运行 我已经下载了 mysqldb 并按照此处的指南进行操作 http cd34 com blog programming python mysql pyth
  • SocketIO + Flask 检测断开连接

    我在这里有一个不同的问题 但意识到它可以简化为 如何检测客户端何时从页面断开连接 关闭其页面或单击链接 换句话说 套接字连接关闭 我想制作一个带有更新用户列表的聊天应用程序 并且我在 Python 上使用 Flask 当用户连接时 浏览器发
  • 在系统托盘中隐藏 tkinter 窗口 [重复]

    这个问题在这里已经有答案了 我正在制作一个程序来提醒我朋友的生日 这样我就不会忘记祝福他们 为此 我制作了两个 tkinter 窗口 1 First one is for entering name and birth date 2 Sec
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • Python SSL X509:KEY_VALUES_MISMATCH

    Python HTTPS server from http server import HTTPServer SimpleHTTPRequestHandler import ssl https stackoverflow com a 408
  • python 线程安全可变对象复制

    Is 蟒蛇的copy http docs python org 2 library copy html模块线程安全吗 如果不是 我应该如何在 python 中以线程安全的方式复制 deepcopy 可变对象 蟒蛇的GIL http en w
  • 查找总和为给定数字的值组合的函数

    这个帖子查找提供的 Sum 值的组合 https stackoverflow com a 20194023 1561176呈现函数subsets with sum 它在数组中查找总和等于给定值的值的组合 但由于这个帖子已经有6年多了 我发这
  • 如何为不同操作系统/Python 版本编译 Python C/C++ 扩展?

    我注意到一些成熟的Python库已经为大多数架构 Win32 Win amd64 MacOS 和Python版本提供了预编译版本 针对不同环境交叉编译扩展的标准方法是什么 葡萄酒 虚拟机 众包 我们使用虚拟机和Hudson http hud

随机推荐

  • BQ40Z50 调试

    一 简介 BQ40Z50 R1的特点与功能 1 这是一颗单芯片解决方案 集成电池 充放电保护 均衡 电量测量三大主要功能 2 支持1 2 3 4节串联锂离子或锂聚合物电池组 二 使用 1 BQ40Z50 R1 评估版一块 2 调试器一个 3
  • 什么是COBOL? COBOL编程说明

    有些技术永不消亡 它们只是逐渐消失在木制品中 向普通软件开发人员询问有关COBOL 面向通用商业语言 的信息 他们会看着您 就像您提到复写纸 含铅汽油或78 RPM记录一样 与Go或Python甚至Pascal或C 之类的现代语言相比 CO
  • winform多文件上传接口服务器,winform向云服务器上传文件

    winform向云服务器上传文件 内容精选 换一换 安装传输工具在本地主机和Windows云服务器上分别安装数据传输工具 将文件上传到云服务器 例如QQ exe 在本地主机和Windows云服务器上分别安装数据传输工具 将文件上传到云服务器
  • C++ tuple元组的基本用法(总结)

    1 元组简介 tuple是一个固定大小的不同类型值的集合 是泛化的std pair 我们也可以把他当做一个通用的结构体来用 不需要创建结构体又获取结构体的特征 在某些情况下可以取代结构体使程序更简洁 直观 std tuple理论上可以有无数
  • 操作型bi研究报告(转)

    操作型bi是bi发展过程中的转折点 传统上认为 bi是从海量历史数据中利用成熟的分析工具发现业务中的模式和趋势 从战略上和战术上辅助决策的一种技术 但是操作型bi改变了这种观点 它将bi从后台搬出来并且嵌入到业务操作流程的细节中 驱动着日以
  • 影之刃3服务器维护,影之刃33月4日维护公告 内容公告预览

    影之刃3 将于3月4日10 00 12 00对全部服务器停服维护 维护期间将无法登录游戏 给您带来的不便敬请谅解 感谢您的理解和支持 本次维护预计持续2小时 维护时间可能延长或提前结束 具体时间请以开服时间为准 维护结束后 我们将为全服玩家
  • 域名能查到服务器信息么,域名查服务器信息

    域名查服务器信息 内容精选 换一换 用户可以通过查询域名注册信息 确认域名所属的DNS服务器信息 然后再根据域名所属的DNS服务器信息进行DNS验证的相关操作 当 Name Servers 显示如所图1示时 则表示域名所属的DNS服务器为华
  • RTX 3080 Linux和Windows 平台兼容性问题

    好不容易 在某电商平台抢到了一块3080显卡 高高兴兴的装机准备大搞游戏开始深度学习 却遇到了很多麻烦 当然经过多方探索 终于也是解决了linux和Windows双平台的兼容性问题 目前Pytorch和TensorFlow都能使用 首先是l
  • Windows系统下如何运行.sh脚本文件

    前言 sh文件是一种命令脚本文件 在Windows系统下可以通过命令行工具打开运行 通常可以使用Git工具来打开运行 sh脚本文件 不过很多第一次使用Git的人 可能对Git工具不熟悉 sh文件在命令行运行时是有固定写法的 下面介绍详细步骤
  • 【Linux】---进程控制(创建、终止、等待、替换)

    文章目录 进程创建 fork 进程退出 进程退出场景 进程退出方法 退出码 exit exit 进程等待 进程等待的方法 wait waitpid 阻塞和非阻塞 进程替换 替换的原理 替换所用到的函数 execl execlp execle
  • shell 字符串处理汇总(查找,替换等等)

    字符串 简称 串 有限字符的序列 数据元素为字符的线性表 是一种数据的逻辑结构 在计算机中可有不同的存储结构 在串上可进行求子串 插入字符 删除字符 置换字符等运算 字符 计算机程序设计及操作时使用的符号 包括字母 数字 空格符 提示符及各
  • 【Java基础知识 3】为何要配置环境变量?

    Java基础教程系列 Java基础教程系列 Java学习路线配套文章 搬砖工逆袭Java架构师 Java经典面试题大全 10万字208道Java经典面试题总结 附答案 简介 Java领域优质创作者 CSDN哪吒公众号作者 Java架构师奋斗
  • 模拟电路设计(33)---电源变换器简介

    概述 电子设备都需要供电 其电能来源于火力 水力 核子发电厂提供的交流电 这些交流电通过电源设备变换为直流电 但是 这种直流电源不符合需要 仍需变换 这称为DC DC变换 常规的变换器是串联线性稳压电源 其调整元件工作于线性放大区 通过的电
  • 学习Kali渗透测试笔记

    Kali渗透测试 一 什么是渗透测试 1 软件测试 2 安全测试与渗透测试 3 渗透测试 二 渗透测试的目标 1 网络硬件设备 2 主机操作系统 3 应用系统 4 数据库系统 三 渗透测试的意义 四 渗透测试的方法分类 1 按照信息掌握程度
  • LiteOrm "cannot be instantiated"

    错误提示 java lang Class
  • 【深度强化学习】(5) DDPG 模型解析,附Pytorch完整代码

    大家好 今天和各位分享一下深度确定性策略梯度算法 Deterministic Policy Gradient DDPG 并基于 OpenAI 的 gym 环境完成一个小游戏 完整代码在我的 GitHub 中获得 https github c
  • 网络管理服务器篇之Apache

    一 软件简介 1 Apache是最流行的Web服务器端软件之一 快速 可靠 可通过简单的API扩展 Perl Python解释器可被编译到服务器中 完全免费 完全源代码开放 如果你需要创建一个每天有数百万人访问的Web服务器 Apache可
  • 【文件上传绕过】五、文件后缀大小写绕过

    文章目录 一 黑名单 二 源码 三 大小写绕过 一 黑名单 本pass禁止上传 php php5 php4 php3 php2 php1 html htm phtml pHp pHp5 pHp4 pHp3 pHp2 pHp1 Html Ht
  • String类详解

    目录 一 创建字符串的四种方式 1 直接赋值 2 通过构造方法创建对象 3 通过字符数组创建对象 4 通过String类的静态方法valueOf 任意数据类型 gt 转为字符串 二 字符串比较相等 equals方法 equalsIgnore
  • ICMP协议Ping方法的Python实现解析

    ICMP协议Ping方法的Python实现解析 说明 本代码适合Windows 没有在其他系统下进行测试 参考对象为https github com samuel python ping 流程 选择目标网址 解析对方ip地址 构造数据报 添