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实现解析 的相关文章

  • Pandas set_levels,如何避免标签排序?

    我使用时遇到问题set levels多索引 from io import StringIO txt Name Height Age Metres A 1 25 B 95 1 df pd read csv StringIO txt heade
  • Python 类型提示 Dict 语法错误 可变默认值是不允许的。使用“默认工厂”

    我不知道为什么解释器会抱怨这个类型的字典 对于这两个实例 我得到一个 不允许可变默认值 使用默认工厂 语法错误 我使用的是 python 3 7 3 from dataclasses import dataclass from typing
  • 让 VoiceChannel.members 和 Guild.members 返回完整列表的问题

    每当我尝试使用 VoiceChannel members 或 Guild members 时 它都不会提供适用成员的完整列表 我从文本命令的上下文中获取 VoiceChannel 和 Guild 如下所示 bot command name
  • 计算另一个字符串中多个字符串的出现次数

    在 Python 2 7 中 给定以下字符串 Spot是一只棕色的狗 斑点有棕色的头发 斑点的头发是棕色的 查找字符串中 Spot brown 和 hair 总数的最佳方法是什么 在示例中 它将返回 8 我正在寻找类似的东西string c
  • matplotlib 图中点的标签

    所以这是一个关于已发布的解决方案的问题 我试图在我拥有的 matplotlib 散点图中的点上放置一些数据标签 我试图在这里模仿解决方案 是否有与 MATLAB 的 datacursormode 等效的 matplotlib https s
  • pandas DataFrame.join 的运行时间是多少(大“O”顺序)?

    这个问题更具概念性 理论性 与非常大的数据集的运行时间有关 所以我很抱歉没有一个最小的例子来展示 我有一堆来自两个不同传感器的数据帧 我需要最终将它们连接成两个very来自两个不同传感器的大数据帧 df snsr1 and df snsr2
  • 多输出堆叠回归器

    一次性问题 我正在尝试构建一个多输入堆叠回归器 添加到 sklearn 0 22 据我了解 我必须结合StackingRegressor and MultiOutputRegressor 经过多次尝试 这似乎是正确的顺序 import nu
  • 如何从Python中的函数返回多个值? [复制]

    这个问题在这里已经有答案了 如何从Python中的函数返回多个变量 您可以用逗号分隔要返回的值 def get name you code return first name last name 逗号表示它是一个元组 因此您可以用括号将值括
  • python multiprocessing 设置生成进程等待

    是否可以生成一些进程并将生成进程设置为等待生成的进程完成 下面是我用过的一个例子 import multiprocessing import time import sys def daemon p multiprocessing curr
  • Windows 上最快的屏幕捕获方法

    我想为Windows平台编写一个截屏程序 但不确定如何捕获屏幕 我知道的唯一方法是使用 GDI 但我很好奇是否还有其他方法可以实现此目的 如果有的话 哪种方法产生的开销最小 速度是首要任务 截屏程序将用于录制游戏镜头 不过 如果这确实缩小了
  • 为什么 web2py 在启动时崩溃?

    我正在尝试让 web2py 在 Ubuntu 机器上运行 所有文档似乎都表明要在 nix 系统上运行它 您需要下载源代码并执行以下操作 蟒蛇 web2py py 我抓住了source http www web2py com examples
  • 矩形函数的数值傅里叶变换

    本文的目的是通过一个众所周知的分析傅里叶变换示例来正确理解 Python 或 Matlab 上的数值傅里叶变换 为此 我选择矩形函数 这里报告了它的解析表达式及其傅立叶变换https en wikipedia org wiki Rectan
  • 如何将特定范围内的标量添加到 numpy 数组?

    有没有一种更简单 更节省内存的方法可以单独在 numpy 中执行以下操作 import numpy as np ar np array a l r ar c a a 0 l ar tolist a r 它可能看起来很原始 但它涉及获取给定数
  • Python - 如何确定解析的 XML 元素的层次结构级别?

    我正在尝试使用 Python 解析 XML 文件中具有特定标记的元素并生成输出 excel 文档 该文档将包含元素并保留其层次结构 我的问题是我无法弄清楚每个元素 解析器在其上迭代 的嵌套深度 XML 示例摘录 3 个元素 它们可以任意嵌套
  • Python GTK+ 画布

    我目前正在通过 PyGobject 学习 GTK 需要画布之类的东西 我已经搜索了文档 发现两个小部件似乎可以完成这项工作 GtkDrawingArea 和 GtkLayout 我需要一些基本函数 如 fillrect 或 drawline
  • Spider 必须返回 Request、BaseItem、dict 或 None,已“设置”

    我正在尝试从以下位置下载所有产品的图像 我的蜘蛛看起来像 from shopclues items import ImgData import scrapy class multipleImages scrapy Spider name m
  • 如果 PyPy 快 6.3 倍,为什么我不应该使用 PyPy 而不是 CPython?

    我已经听到很多关于PyPy http en wikipedia org wiki PyPy项目 他们声称它比现有技术快 6 3 倍CPython http en wikipedia org wiki CPython口译员开启他们的网站 ht
  • 重新分配唯一值 - pandas DataFrame

    我在尝试着assign unique值在pandas df给特定的个人 For the df below Area and Place 会一起弥补unique不同的价值观jobs 这些值将分配给个人 总体目标是使用尽可能少的个人 诀窍在于这
  • 如何使用 Boto3 启动具有 IAM 角色的 EC2 实例?

    我无法弄清楚如何使用指定的 IAM 角色在 Boto3 中启动 EC2 实例 以下是迄今为止我如何成功创建实例的一些示例代码 import boto3 ec2 boto3 resource ec2 region name us west 2
  • 如何将 Django 中的权限添加到模型并使用 shell 进行测试

    我在模型中添加了 Meta 类并同步了数据库 然后在 shell 中创建了一个对象 它返回 false 所以我真的无法理解错误在哪里或者缺少什么是否在其他文件中可能存在某种配置 class Employer User Employer in

随机推荐

  • 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地址 构造数据报 添