Python socket 编写一个Ping 程序 利用网际层icmp协议 计算机网络

计算机网络课程设计,要编写一个Ping 程序 或者 tracert 程序 。

不使用C/C++ ,Java 不提供传输层一下的控制。只好使用Python来编写

讲解参考 https://www.cnblogs.com/JetpropelledSnake/p/9177770.html

参考 https://wordpress.youran.me/python-raw-socket-programming/

参考 https://www.cnblogs.com/JenningsMao/p/9487465.html

参考 python struct的用法 https://www.cnblogs.com/sexyboy/p/8509666.html

源码来源 https://github.com/Lingerhk/hacking_script/blob/master/net_attacking/icmp_ping_tool.py

源码是python 2 写的 

改一下成python 3 


# -*- coding: utf-8 -*-
import os
import argparse
import socket
import struct
import select
import time
# 请求回显头
ICMP_ECHO_REQUEST = 8  # Platform specific
DEFAULT_TIMEOUT = 2
DEFAULT_COUNT = 1


class Pinger(object):
    """ Pings to a host -- the Pythonic way"""

    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):
        """  Verify the packet integritity """
        sum = 0
        max_count = (len(source_string) / 2) * 2
        count = 0
        while count < max_count:
            val = source_string[count + 1] * 256 + source_string[count]
            sum = sum + val
            sum = sum & 0xffffffff
            count = count + 2

        if max_count < len(source_string):
            sum = sum + ord(source_string[len(source_string) - 1])
            sum = sum & 0xffffffff

        sum = (sum >> 16) + (sum & 0xffff)
        sum = sum + (sum >> 16)
        answer = ~sum
        answer = answer & 0xffff
        answer = answer >> 8 | (answer << 8 & 0xff00)
        return answer

    def receive_pong(self, sock, ID, timeout):
        """
        Receive ping from the socket.
        """
        time_remaining = timeout
        while True:
            start_time = time.time()
            readable = select.select([sock], [], [], time_remaining)
            time_spent = (time.time() - start_time)
            if readable[0] == []:  # Timeout
                return

            time_received = time.time()
            recv_packet, addr = sock.recvfrom(1024)
            icmp_header = recv_packet[20:28]
            type, code, checksum, packet_ID, sequence = struct.unpack(
                "bbHHh", icmp_header
            )
            if packet_ID == ID:
                bytes_In_double = struct.calcsize("d")
                time_sent = struct.unpack("d", recv_packet[28:28 + bytes_In_double])[0]
                return time_received - time_sent

            time_remaining = time_remaining - time_spent
            if time_remaining <= 0:
                return

    def send_ping(self, sock, ID):
        """
        Send ping to the target host
        """
        target_addr = socket.gethostbyname(self.target_host)

        my_checksum = 0

        # Create a dummy heder with a 0 checksum.
        header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
        bytes_In_double = struct.calcsize("d")
        data = (192 - bytes_In_double) * "R"
        data = struct.pack("d", time.time()) + bytes(data.encode('utf-8'))

        # Get the checksum on the data and the dummy header.
        my_checksum = self.do_checksum(header + data)
        header = struct.pack(
            "bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1
        )
        packet = header + data
        sock.sendto(packet, (target_addr, 1))

    def ping_once(self):
        """
        Returns the delay (in seconds) or none on timeout.
        """
        icmp = socket.getprotobyname("icmp")
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
        except socket.error as e:
            if e.errno == 1:
                # Not superuser, so operation not permitted
                e.msg += "ICMP messages can only be sent from root user processes"
                raise socket.error(e.msg)
        except Exception as e:
            print("Exception: %s" % (e))

        my_ID = os.getpid() & 0xFFFF

        self.send_ping(sock, my_ID)
        delay = self.receive_pong(sock, my_ID, self.timeout)
        sock.close()
        return delay

    def ping(self):
        """
        Run the ping process
        """
        for i in range(self.count):
            print("Ping to %s..." % self.target_host, )
            try:
                delay = self.ping_once()
            except socket.gaierror as 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" % delay)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Python ping')
    parser.add_argument('host', action="store", help=u'主机名')
    given_args = parser.parse_args()
    target_host = given_args.host
    pinger = Pinger(target_host=target_host)
    pinger.ping()

 这是 命令行代码

下面这个是我修改过后 根据课程设计要求加入GUI的代码

# -*- coding: utf-8 -*-
import os
import argparse
import socket
import struct
import select
import threading
import time
# 请求回显头
from concurrent.futures.thread import ThreadPoolExecutor
from tkinter import *
from tkinter import ttk

ICMP_ECHO_REQUEST = 8  # Platform specific
DEFAULT_TIMEOUT = 2
DEFAULT_COUNT = 1
# 创建锁
lock= threading.Lock()
Running = True
class Pinger(object):
    """ Pings to a host -- the Pythonic way"""

    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):
        """  Verify the packet integritity """
        sum = 0
        max_count = (len(source_string) / 2) * 2
        count = 0
        while count < max_count:
            val = source_string[count + 1] * 256 + source_string[count]
            sum = sum + val
            sum = sum & 0xffffffff
            count = count + 2

        if max_count < len(source_string):
            sum = sum + ord(source_string[len(source_string) - 1])
            sum = sum & 0xffffffff

        sum = (sum >> 16) + (sum & 0xffff)
        sum = sum + (sum >> 16)
        answer = ~sum
        answer = answer & 0xffff
        answer = answer >> 8 | (answer << 8 & 0xff00)
        return answer

    def receive_pong(self, sock, ID, timeout):
        """
        Receive ping from the socket.
        """
        time_remaining = timeout
        while True:
            start_time = time.time()
            readable = select.select([sock], [], [], time_remaining)
            time_spent = (time.time() - start_time)
            if readable[0] == []:  # Timeout
                return

            time_received = time.time()
            recv_packet, addr = sock.recvfrom(1024)
            icmp_header = recv_packet[20:28]
            type, code, checksum, packet_ID, sequence = struct.unpack(
                "bbHHh", icmp_header
            )
            if packet_ID == ID:
                bytes_In_double = struct.calcsize("d")
                time_sent = struct.unpack("d", recv_packet[28:28 + bytes_In_double])[0]
                return time_received - time_sent

            time_remaining = time_remaining - time_spent
            if time_remaining <= 0:
                return

    def send_ping(self, sock, ID):
        """
        Send ping to the target host
        """
        target_addr = socket.gethostbyname(self.target_host)

        my_checksum = 0

        # Create a dummy heder with a 0 checksum.
        header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
        bytes_In_double = struct.calcsize("d")
        data = (192 - bytes_In_double) * "R"
        data = struct.pack("d", time.time()) + bytes(data.encode('utf-8'))

        # Get the checksum on the data and the dummy header.
        my_checksum = self.do_checksum(header + data)
        header = struct.pack(
            "bbHHh", ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1
        )
        packet = header + data
        sock.sendto(packet, (target_addr, 1))

    def ping_once(self):
        """
        Returns the delay (in seconds) or none on timeout.
        """
        icmp = socket.getprotobyname("icmp")
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
        except socket.error as e:
            if e.errno == 1:
                # Not superuser, so operation not permitted
                e.msg += "ICMP messages can only be sent from root user processes"
                raise socket.error(e.msg)
        except Exception as e:
            print("Exception: %s" % (e))

        my_ID = os.getpid() & 0xFFFF

        self.send_ping(sock, my_ID)
        delay = self.receive_pong(sock, my_ID, self.timeout)
        sock.close()
        return delay

    def ping(self):
        """
        Run the ping process
        """
        for i in range(self.count):
            #print("Ping to %s..." % self.target_host, )
            try:
                delay = self.ping_once()
            except socket.gaierror as e:
                return -2
                print("Ping failed. (socket error: '%s')" % e[1])
                break

            if delay == None:
                #return self.timeout
                return -2
                print("Ping failed. (timeout within %ssec.)" % self.timeout)
            else:
                delay = delay * 1000
                return delay
                print("Get ping in %0.4fms" % delay)

def closePool():
    global Running
    Running= False
    print("hah")

def clearTb():
    x = tb.get_children()
    for item in x:
        tb.delete(item)
    numlb['text']=0


def insertRes():
    global Running
    Running = True
    clearTb()
    timeout= int(t6.get())/1000
    threadnum = int(t7.get())
    print(threadnum)
    print(timeout)
    start=int(t4.get())
    end=int(t5.get())
    #run("www.baidu.com")
    pool = ThreadPoolExecutor(threadnum)
    for i in range(start,end):
        ip = t1.get() + '.' + t2.get() + '.' + t3.get() + '.' + str(i)
        v =pool.submit(run,ip,i,timeout)




def run(ipstart,i,timeout):
    global Running
    if(Running==False):
        return
    ping = Pinger(ipstart,timeout=timeout)
    res1=ping.ping()
    res2=ping.ping()
    res3=ping.ping()
    if(res1==-2 or res2==-2 or res3==-2):
        tb.insert("", i, value=(ipstart, "超时或错误"))
    else:
        res=(res1+res2+res3)/ 3
        res=str(round(res,4))+'ms'
        tb.insert("", i, value=(ipstart, res))
        lock.acquire()
        num = int(numlb['text'])
        num +=1
        numlb['text']=num
        lock.release()





if __name__ == '__main__':
    # 创建  窗口
    root=Tk()
    # 先初始化

    root.title("一个简单的Python Ping程序         by Duskry Ren ")
    root.geometry("720x500")
    root.resizable(False, False)
    frame1= Frame(root)
    frame1.pack()
    #frame1.place(x=0,y=0,width=720,height=50)
    lb1=Label(frame1,text='   IP地址:',font=20)
    lb1.pack(side=LEFT)
    t1 = Entry(frame1,font=20,textvariable=IntVar,width=6)
    t1.pack(side=LEFT)
    t1.insert(0,'10')
    lb2 = Label(frame1, text='.', font=20)
    lb2.pack(side=LEFT)
    t2 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t2.pack(side=LEFT)
    t2.insert(0, "1")
    lb3 = Label(frame1, text='.', font=20)
    lb3.pack(side=LEFT)
    t3 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t3.pack(side=LEFT)
    t3.insert(0,"11")
    lb3 = Label(frame1, text='从', font=20)
    lb3.pack(side=LEFT)
    t4 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t4.pack(side=LEFT)
    t4.insert(0,"0")
    lb3 = Label(frame1, text='到', font=20)
    lb3.pack(side=LEFT)
    t5 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t5.pack(side=LEFT)
    t5.insert(0,"10")
    lb3 = Label(frame1, text=' 超时:', font=20)
    lb3.pack(side=LEFT)
    t6 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t6.pack(side=LEFT)
    t6.insert(0,"2000")
    lb3 = Label(frame1, text=' 线程:', font=20)
    lb3.pack(side=LEFT)
    t7 = Entry(frame1, font=20, textvariable=IntVar, width=6)
    t7.pack(side=LEFT)
    t7.insert(0,3)
    frame2 = Frame(root,width=720,height=200)
    frame2.pack()
    scroll1 = Scrollbar(frame2)
    scroll1.pack(side=RIGHT, fill=Y)
    tb = ttk.Treeview(frame2,yscrollcommand=scroll1.set,show="headings",height=12)
    tb['columns']=("ip","time")
    tb.column("ip",width=320,anchor='center')
    tb.column("time",width=320,anchor='center')
    tb.heading("ip",text='ip')
    tb.heading('time',text='状态')
    tb.pack()
    frame3 = Frame(root,bg='gray')
    frame3.pack(fill=X)
    btn1=ttk.Button(frame3,text="开始",command=insertRes)
    btn1.pack(side=LEFT)
    btn2= ttk.Button(frame3,text='结束',command=closePool)
    btn2.pack(side=LEFT)
    btn3= ttk.Button(frame3,text="清空",command=clearTb)
    btn3.pack(side=LEFT)
    numlb = Label(frame3,text='0')
    numlb.pack(side =RIGHT)
    lb = Label(frame3, text="响应数:")
    lb.pack(side=RIGHT)
    #text = Text(frame2,font=26,yscrollcommand=scroll1.set)
    #text.pack(fill=BOTH, expand=YES)

    #insertRes()

    root.mainloop()
    # parser = argparse.ArgumentParser(description='Python ping')
    # parser.add_argument('host', action="store", help=u'主机名')
    # given_args = parser.parse_args()
    # target_host = given_args.host
    #pinger = Pinger(target_host='www.baidu.com')
    #pinger.ping()

发布了22 篇原创文章 · 获赞 2 · 访问量 881

猜你喜欢

转载自blog.csdn.net/weixin_41685373/article/details/103732519