免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 22330 | 回复: 16
打印 上一主题 下一主题

从网上找的 ping 源代码 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-05-31 22:46 |只看该作者 |倒序浏览
标准ping程序的python实现。代码不错,注释的也不错,里边还有icmp的报文结构。
http://www.gnist.org/~lars/code/ping/ping.py

论坛徽章:
0
2 [报告]
发表于 2005-05-31 23:32 |只看该作者

从网上找的 ping 源代码

沙发...对我来说值得一读

论坛徽章:
0
3 [报告]
发表于 2005-05-31 23:33 |只看该作者

从网上找的 ping 源代码

方便大家阅读我把代码复制过来了

  1. #!/usr/bin/env python
  2. # -*- coding: iso-8859-1 -*-
  3. """ping.py

  4. ping.py uses the ICMP protocol's mandatory ECHO_REQUEST
  5. datagram to elicit an ICMP ECHO_RESPONSE from a
  6. host or gateway.

  7. Copyright (C) 2004 - Lars Strand <lars strand at gnist org>;

  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License
  10. as published by the Free Software Foundation; either version 2
  11. of the License, or (at your option) any later version.

  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.

  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  19. Must be running as root, or write a suid-wrapper. Since newer *nix
  20. variants, the kernel ignores the set[ug]id flags on #! scripts for
  21. security reasons

  22. RFC792, echo/reply message:

  23.   0                   1                   2                   3
  24.   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  25. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  26. |     Type      |     Code      |          Checksum             |
  27. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  28. |           Identifier          |        Sequence Number        |
  29. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  30. |     Data ...
  31. +-+-+-+-+-


  32. TODO:
  33. - do not create socket inside 'while' (but if not: ipv6 won't work)
  34. - add support for broadcast/multicast
  35. - add support for own payload string

  36. CHANGELOG:
  37. DONE -->; bugfix from Filip Van Raemdonck mechanix debian org
  38. DONE -->; add more support for modules (raise instead of sys.exit)
  39. DONE -->; locale func names
  40. DONE -->; package def
  41. DONE -->; some code cleanup

  42. """

  43. import sys
  44. import os
  45. import struct
  46. import array
  47. import time
  48. import select
  49. import binascii
  50. import math
  51. import getopt
  52. import string
  53. import socket

  54. # total size of data (payload)
  55. ICMP_DATA_STR = 56  

  56. # initial values of header variables
  57. ICMP_TYPE = 8
  58. ICMP_TYPE_IP6 = 128
  59. ICMP_CODE = 0
  60. ICMP_CHECKSUM = 0
  61. ICMP_ID = 0
  62. ICMP_SEQ_NR = 0

  63. # Package definitions.
  64. __program__   = 'ping'
  65. __version__   = '0.5a'
  66. __date__      = '2004/15/12'
  67. __author__    = 'Lars Strand <lars at unik no>;'
  68. __licence__   = 'GPL'
  69. __copyright__ = 'Copyright (C) 2004 Lars Strand'

  70. def _construct(id, size, ipv6):
  71.     """Constructs a ICMP echo packet of variable size
  72.     """

  73.     # size must be big enough to contain time sent
  74.     if size < int(struct.calcsize("d")):
  75.         _error("packetsize to small, must be at least %d" % int(struct.calcsize("d")))
  76.    
  77.     # construct header
  78.     if ipv6:
  79.         header = struct.pack('BbHHh', ICMP_TYPE_IP6, ICMP_CODE, ICMP_CHECKSUM, \
  80.                              ICMP_ID, ICMP_SEQ_NR+id)
  81.     else:
  82.         header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, ICMP_CHECKSUM, \
  83.                              ICMP_ID, ICMP_SEQ_NR+id)

  84.     # if size big enough, embed this payload
  85.     load = "-- IF YOU ARE READING THIS YOU ARE A NERD! --"
  86.    
  87.     # space for time
  88.     size -= struct.calcsize("d")

  89.     # construct payload based on size, may be omitted :)
  90.     rest = ""
  91.     if size >; len(load):
  92.         rest = load
  93.         size -= len(load)

  94.     # pad the rest of payload
  95.     rest += size * "X"

  96.     # pack
  97.     data = struct.pack("d", time.time()) + rest
  98.     packet = header + data          # ping packet without checksum
  99.     checksum = _in_cksum(packet)    # make checksum

  100.     # construct header with correct checksum
  101.     if ipv6:
  102.         header = struct.pack('BbHHh', ICMP_TYPE_IP6, ICMP_CODE, checksum, \
  103.                              ICMP_ID, ICMP_SEQ_NR+id)
  104.     else:
  105.         header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, checksum, ICMP_ID, \
  106.                              ICMP_SEQ_NR+id)

  107.     # ping packet *with* checksum
  108.     packet = header + data

  109.     # a perfectly formatted ICMP echo packet
  110.     return packet

  111. def _in_cksum(packet):
  112.     """THE RFC792 states: 'The 16 bit one's complement of
  113.     the one's complement sum of all 16 bit words in the header.'

  114.     Generates a checksum of a (ICMP) packet. Based on in_chksum found
  115.     in ping.c on FreeBSD.
  116.     """

  117.     # add byte if not dividable by 2
  118.     if len(packet) & 1:              
  119.         packet = packet + '\0'

  120.     # split into 16-bit word and insert into a binary array
  121.     words = array.array('h', packet)
  122.     sum = 0

  123.     # perform ones complement arithmetic on 16-bit words
  124.     for word in words:
  125.         sum += (word & 0xffff)

  126.     hi = sum >;>; 16
  127.     lo = sum & 0xffff
  128.     sum = hi + lo
  129.     sum = sum + (sum >;>; 16)
  130.    
  131.     return (~sum) & 0xffff # return ones complement

  132. def pingNode(alive=0, timeout=1.0, ipv6=0, number=sys.maxint, node=None, \
  133.              flood=0, size=ICMP_DATA_STR):
  134.     """Pings a node based on input given to the function.
  135.     """

  136.     # if no node, exit
  137.     if not node:
  138.         _error("")

  139.     # if not a valid host, exit
  140.     if ipv6:
  141.         if socket.has_ipv6:
  142.             try:
  143.                 info, port = socket.getaddrinfo(node, None)
  144.                 host = info[4][0]
  145.                 # do not print ipv6 twice if ipv6 address given as node
  146.                 if host == node:
  147.                     noPrintIPv6adr = 1
  148.             except:
  149.                 _error("cannot resolve %s: Unknow host" % node)
  150.         else:
  151.             _error("No support for IPv6 on this plattform")
  152.     else:    # IPv4
  153.         try:
  154.             host = socket.gethostbyname(node)
  155.         except:
  156.             _error("cannot resolve %s: Unknow host" % node)

  157.     # trying to ping a network?
  158.     if not ipv6:
  159.         if int(string.split(host, ".")[-1]) == 0:
  160.             _error("no support for network ping")

  161.     # do some sanity check
  162.     if number == 0:
  163.         _error("invalid count of packets to transmit: '%s'" % str(a))
  164.     if alive:
  165.         number = 1

  166.     # Send the ping(s)
  167.     start = 1; mint = 999; maxt = 0.0; avg = 0.0
  168.     lost = 0; tsum = 0.0; tsumsq = 0.0

  169.     # tell the user what we do
  170.     if not alive:
  171.         if ipv6:
  172.             # do not print the ipv6 twice if ip adress given as node
  173.             # (it can be to long in term window)
  174.             if noPrintIPv6adr == 1:
  175.                 # add 40 (header) + 8 (icmp header) + payload
  176.                 print "PING %s : %d data bytes (40+8+%d)" % (str(node), \
  177.                                                              40+8+size, size)
  178.             else:
  179.                 # add 40 (header) + 8 (icmp header) + payload
  180.                 print "PING %s (%s): %d data bytes (40+8+%d)" % (str(node), \
  181.                                                                  str(host), 40+8+size, size)
  182.         else:
  183.             # add 20 (header) + 8 (icmp header) + payload
  184.             print "PING %s (%s): %d data bytes (20+8+%d)" % (str(node), str(host), \
  185.                                                              20+8+size, size)
  186.         
  187.     # trap ctrl-d and ctrl-c
  188.     try:
  189.         
  190.         # send the number of ping packets as given
  191.         while start <= number:
  192.             lost += 1 # in case user hit ctrl-c
  193.             
  194.             # create the IPv6/IPv4 socket
  195.             if ipv6:
  196.                 # can not create a raw socket if not root or setuid to root
  197.                 try:
  198.                     pingSocket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, \
  199.                                                socket.getprotobyname("ipv6-icmp"))
  200.                 except socket.error, e:
  201.                     print "socket error: %s" % e
  202.                     _error("You must be root (uses raw sockets)" % os.path.basename(sys.argv[0]))
  203.                     
  204.             # IPv4
  205.             else:
  206.                 # can not create a raw socket if not root or setuid to root
  207.                 try:
  208.                     pingSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, \
  209.                                                socket.getprotobyname("icmp"))
  210.                 except socket.error, e:
  211.                     print "socket error: %s" % e
  212.                     _error("You must be root (%s uses raw sockets)" % os.path.basename(sys.argv[0]))
  213.                
  214.             packet = _construct(start, size, ipv6) # make a ping packet

  215.             # send the ping
  216.             try:
  217.                 pingSocket.sendto(packet,(node,1))
  218.             except socket.error, e:
  219.                 _error("socket error: %s" % e)

  220.             # reset values
  221.             pong = ""; iwtd = []

  222.             # wait until there is data in the socket
  223.             while 1:
  224.                 # input, output, exceptional conditions
  225.                 iwtd, owtd, ewtd = select.select([pingSocket], [], [], timeout)
  226.                 break # no data and timout occurred

  227.             # data on socket - this means we have an answer
  228.             if iwtd:  # ok, data on socket
  229.                 endtime = time.time()  # time packet received
  230.                 # read data (we only need the header)
  231.                 pong, address = pingSocket.recvfrom(size+48)
  232.                 lost -= 1 # in case user hit ctrl-c

  233.                 # examine packet
  234.                 # fetch TTL from IP header
  235.                 if ipv6:
  236.                     # since IPv6 header and any extension header are never passed
  237.                     # to a raw socket, we can *not* get hoplimit field..
  238.                     # I hoped that a socket option would help, but it's not
  239.                     # supported:
  240.                     #   pingSocket.setsockopt(IPPROTO_IPV6, IPV6_RECVHOPLIMIT, 1)
  241.                     # so we can't fetch hoplimit..

  242.                     # fetch hoplimit
  243.                     #rawPongHop = struct.unpack("c", pong[7])[0]

  244.                     # fetch pong header
  245.                     pongHeader = pong[0:8]
  246.                     pongType, pongCode, pongChksum, pongID, pongSeqnr = \
  247.                               struct.unpack("bbHHh", pongHeader)

  248.                     # fetch starttime from pong
  249.                     starttime = struct.unpack("d", pong[8:16])[0]

  250.                 # IPv4
  251.                 else:
  252.                     # time to live
  253.                     rawPongHop = struct.unpack("s", pong[8])[0]

  254.                     # convert TTL from 8 bit to 16 bit integer
  255.                     pongHop = int(binascii.hexlify(str(rawPongHop)), 16)

  256.                     # fetch pong header
  257.                     pongHeader = pong[20:28]
  258.                     pongType, pongCode, pongChksum, pongID, pongSeqnr = \
  259.                               struct.unpack("bbHHh", pongHeader)

  260.                     # fetch starttime from pong
  261.                     starttime = struct.unpack("d", pong[28:36])[0]

  262.                 # valid ping packet received?
  263.                 if not pongSeqnr == start:
  264.                     pong = None

  265.             # NO data on socket - timeout waiting for answer
  266.             if not pong:
  267.                 if alive:
  268.                     print "no reply from %s (%s)" % (str(node), str(host))
  269.                 else:
  270.                     print "ping timeout: %s (icmp_seq=%d) " % (host, start)

  271.                 # do not wait if just sending one packet
  272.                 if number != 1 and start < number:
  273.                     time.sleep(flood ^ 1)
  274.                 start += 1
  275.                 continue  # lost a packet - try again

  276.             triptime  = endtime - starttime # compute RRT
  277.             tsum     += triptime            # triptime for all packets (stddev)
  278.             tsumsq   += triptime * triptime # triptime^2  for all packets (stddev)

  279.             # compute statistic
  280.             maxt = max ((triptime, maxt))
  281.             mint = min ((triptime, mint))

  282.             if alive:
  283.                 print str(node) + " (" + str(host) +") is alive"
  284.             else:
  285.                 if ipv6:
  286.                     # size + 8 = payload + header
  287.                     print "%d bytes from %s: icmp_seq=%d time=%.5f ms" % \
  288.                           (size+8, host, pongSeqnr, triptime*1000)
  289.                 else:
  290.                     print "%d bytes from %s: icmp_seq=%d ttl=%s time=%.5f ms" % \
  291.                           (size+8, host, pongSeqnr, pongHop, triptime*1000)

  292.             # do not wait if just sending one packet
  293.             if number != 1 and start < number:
  294.                 # if flood = 1; do not sleep - just ping               
  295.                 time.sleep(flood ^ 1) # wait before send new packet

  296.             # the last thing to do is update the counter - else the value
  297.             # (can) get wrong when computing summary at the end (if user
  298.             # hit ctrl-c when pinging)
  299.             start += 1
  300.             # end ping send/recv while

  301.     # if user ctrl-d or ctrl-c
  302.     except (EOFError, KeyboardInterrupt):
  303.         # if user disrupts ping, it is most likly done before
  304.         # the counter get updates - if do not update it here, the
  305.         # summary get all wrong.
  306.         start += 1
  307.         pass

  308.     # compute and print som stats
  309.     # stddev computation based on ping.c from FreeBSD
  310.     if start != 0 or lost >; 0:  # do not print stats if 0 packet sent
  311.         start -= 1              # since while is '<='
  312.         avg = tsum / start      # avg round trip
  313.         vari = tsumsq / start - avg * avg
  314.         # %-packet lost
  315.         if start == lost:
  316.             plost = 100
  317.         else:
  318.             plost = (lost/start)*100

  319.         if not alive:
  320.             print "\n--- %s ping statistics ---" % node
  321.             print "%d packets transmitted, %d packets received, %d%% packet loss" % \
  322.                   (start, start-lost, plost)
  323.             # don't display summary if 100% packet-loss
  324.             if plost != 100:
  325.                 print "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms" % \
  326.                       (mint*1000, (tsum/start)*1000, maxt*1000, math.sqrt(vari)*1000)

  327.     pingSocket.close()
  328.    
  329. def _error(err):
  330.     """Exit if running standalone, else raise an exception
  331.     """

  332.     if __name__ == '__main__':
  333.         print "%s: %s" % (os.path.basename(sys.argv[0]), str(err))
  334.         print "Try `%s --help' for more information." % os.path.basename(sys.argv[0])
  335.         sys.exit(1)
  336.     else:
  337.         raise Exception, str(err)
  338.    
  339. def _usage():
  340.     """Print usage if run as a standalone program
  341.     """
  342.     print """usage: %s [OPTIONS] HOST
  343. Send ICMP ECHO_REQUEST packets to network hosts.

  344. Mandatory arguments to long options are mandatory for short options too.
  345.   -c, --count=N    Stop after sending (and receiving) 'N' ECHO_RESPONSE
  346.                    packets.
  347.   -s, --size=S     Specify the number of data bytes to be sent. The default
  348.                    is 56, which translates into 64 ICMP data bytes when
  349.                    combined with the 8 bytes of ICMP header data.
  350.   -f, --flood      Flood ping. Outputs packets as fast as they come back. Use
  351.                    with caution!
  352.   -6, --ipv6       Ping using IPv6.
  353.   -t, --timeout=s  Specify a timeout, in seconds, before a ping packet is
  354.                    considered 'lost'.
  355.   -h, --help       Display this help and exit

  356. Report bugs to lars [at] gnist org""" % os.path.basename(sys.argv[0])


  357. if __name__ == '__main__':
  358.     """Main loop
  359.     """

  360.     # version control
  361.     version = string.split(string.split(sys.version)[0][:3], ".")
  362.     if map(int, version) < [2, 3]:
  363.         _error("You need Python ver 2.3 or higher to run!")

  364.     try:
  365.         # opts = arguments recognized,
  366.         # args = arguments NOT recognized (leftovers)
  367.         opts, args = getopt.getopt(sys.argv[1:-1], "hat:6c:fs:", \
  368.                                    ["help", "alive", "timeout=", "ipv6", \
  369.                                     "count=", "flood", "packetsize="])
  370.     except getopt.GetoptError:
  371.         # print help information and exit:
  372.         _error("illegal option(s) -- " + str(sys.argv[1:]))

  373.     # test whether any host given
  374.     if len(sys.argv) >;= 2:
  375.         node = sys.argv[-1:][0]   # host to be pinged
  376.         if node[0] == '-' or node == '-h' or node == '--help' :  
  377.             _usage()
  378.     else:
  379.         _error("No arguments given")

  380.     if args:
  381.         _error("illegal option -- %s" % str(args))
  382.         
  383.     # default variables
  384.     alive = 0; timeout = 1.0; ipv6 = 0; count = sys.maxint;
  385.     flood = 0; size = ICMP_DATA_STR

  386.     # run through arguments and set variables
  387.     for o, a in opts:
  388.         if o == "-h" or o == "--help":    # display help and exit
  389.             _usage()
  390.             sys.exit(0)
  391.         if o == "-t" or o == "--timeout": # timeout before "lost"
  392.             try:
  393.                 timeout = float(a)
  394.             except:
  395.                 _error("invalid timout: '%s'" % str(a))
  396.         if o == "-6" or o == "--ipv6":    # ping ipv6
  397.             ipv6 = 1
  398.         if o == "-c" or o == "--count":   # how many pings?
  399.             try:
  400.                 count = int(a)
  401.             except:
  402.                 _error("invalid count of packets to transmit: '%s'" % str(a))
  403.         if o == "-f" or o == "--flood":   # no delay between ping send
  404.             flood = 1
  405.         if o == "-s" or o == "--packetsize":  # set the ping payload size
  406.             try:
  407.                 size = int(a)
  408.             except:
  409.                 _error("invalid packet size: '%s'" % str(a))
  410.         # just send one packet and say "it's alive"
  411.         if o == "-a" or o == "--alive":   
  412.             alive = 1

  413.     # here we send
  414.     pingNode(alive=alive, timeout=timeout, ipv6=ipv6, number=count, \
  415.              node=node, flood=flood, size=size)
  416.     # if we made it this far, do a clean exit
  417.     sys.exit(0)

  418. ### end
复制代码

论坛徽章:
0
4 [报告]
发表于 2005-05-31 23:54 |只看该作者

从网上找的 ping 源代码

很好

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-03 17:23:07综合交流区版块每日发帖之星
日期:2015-08-19 06:20:00综合交流区版块每日发帖之星
日期:2015-09-15 06:20:00
5 [报告]
发表于 2005-06-01 19:11 |只看该作者

从网上找的 ping 源代码

看不太懂

论坛徽章:
0
6 [报告]
发表于 2005-06-03 00:25 |只看该作者

从网上找的 ping 源代码

墙啊!!顶

论坛徽章:
0
7 [报告]
发表于 2005-06-03 21:07 |只看该作者

从网上找的 ping 源代码

现在还看不明白,不过很快会明白的

论坛徽章:
0
8 [报告]
发表于 2005-07-08 07:07 |只看该作者

从网上找的 ping 源代码

good

论坛徽章:
0
9 [报告]
发表于 2005-07-15 23:20 |只看该作者

从网上找的 ping 源代码

好像用python写的啊.

但是不太明.

论坛徽章:
0
10 [报告]
发表于 2005-07-17 11:32 |只看该作者

从网上找的 ping 源代码

8页纸,我打印出来慢慢研究~
谢谢楼主
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP