python中网络相关的包和函数

一些概念

  • 文件描述符
    • 可以是一个整数形式的文件描述符,比如 sys.stdin.fileno() 的返回结果,或为 io.IOBase 对象,比如 sys.stdin 提供一个 fileno(),可返回一个真正的文件描述符。

常用包

socket

  • 比较底层的API接口,该模块提供对 BSD套接字接口的访问。它适用于所有现代 Unix 系统、Windows、MacOS 以及可能的其他平台。
  • 每一个socket name都是一个地址族(address family) ,常用的地址族就是AF_INET(host,port) 以及 AF_UNIX(string形式返回的bytes-like object) [其他的AF还有很多… 比如AF_INET6 ]

    reference: 官方API:address family

    • 所以说有时候会看到sock.getsockname()[1],如果采用的是AF_INET,[0] 就是host ip ( in string format ),[1]就是port ( in int format )
      • 但,也可能采用的是AF_UNIX地址,这个是在socket创建的时候指定的

fcntl

  • 用于操控文件描述符,实际上是系统的API,python中有对应的包

  • python 使用ioctl() 获得网卡IP 和MAC地址

    • 代码
    from fcntl import ioctl 
    import socket
    import struct
    import sys
     
    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    	try:
    		ip=ioctl(sock.fileno(),0x8915,struct.pack('64s','eth0'))
    		ip=socket.inet_ntoa(ip[20:24])
    		print ip
    except:
    		print sys.exc_info()
    
    • 我理解SIOCGIFADDR的意思是 socket IO get Interface Address

    more reference about ioctl : 知乎的函数API讲解

struct

  • 用于格式化/解析字符串
    • struct.pack(fmt,v1,v2,…) --> a packed string
    • struct.unpack(fmt,string) --> a tuple of string
    • reference : 这个blog不错的

some demo codes

  • extras/sflow.py in sflow-rt 居然还可以显示拓扑
    from mininet.net import Mininet
    from mininet.log import info
    from mininet.util import quietRun
    from os import listdir, environ
    from json import dumps
    from re import match
    from fcntl import ioctl
    from array import array
    from struct import pack, unpack
    from sys import maxsize
    import socket
    import sys
    
    try:
      from urllib.request import build_opener, HTTPHandler, Request
    except ImportError:
      from urllib2 import build_opener, HTTPHandler, Request
    
    
    def wrapper(fn):
      def getIfInfo(dst):
          is_64bits = maxsize > 2**32
          struct_size = 40 if is_64bits else 32
          s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # AF and stream type
          max_possible = 8  # initial value
          while True:
              bytes = max_possible * struct_size
              names = array('B')  #!
              for i in range(0, bytes):
                  names.append(0)
              outbytes = unpack(  # struct.unpack(format, buffer) 
                  'iL', # 目前猜测是是 integer long
                  ioctl(  # 根据命令(2nd para),对fd执行操作(1st para),读写缓冲区((3rd para)) --> return buffer
                      s.fileno(), # 返回文件描述符fd,which可以做select()等
                      0x8912,  # SIOCGIFCONF 对应的值
                      pack('iL', bytes,
                            names.buffer_info()[0])))[0]
              if outbytes == bytes:
                  max_possible *= 2
              else:
                  break
    
          s.connect((dst, 0))
          ip = s.getsockname()[0]
          for i in range(0, outbytes, struct_size):
              addr = socket.inet_ntoa(names[i + 20:i + 24])
              if addr == ip:
                  name = names[i:i + 16]
                  try:
                      name = name.tobytes().decode('utf-8')
                  except AttributeError:
                      name = name.tostring()
                  name = name.split('\0', 1)[0]
                  return (name, addr)
    
      def configSFlow(net, collector, ifname, sampling, polling):
        """ 创建sflow设置的命令行,调用 进行执行
        Args:
            net ([type]): [description]
            collector ([type]): [description]
            ifname ([type]): [description]
            sampling ([type]): [description]
            polling ([type]): [description]
        """
        info("*** Enabling sFlow:\n")
        sflow = 'ovs-vsctl -- --id=@sflow create sflow agent=%s target=%s sampling=%s polling=%s --' % (ifname, collector, sampling, polling)
        for s in net.switches:
            sflow += ' -- set bridge %s sflow=@sflow' % s
        info(' '.join([s.name for s in net.switches]) + "\n")
        quietRun(sflow) # TODO 立刻and后台执行?
    
      def sendTopology(net, agent, collector):
        info("*** Sending topology\n")
        topo = {
          
          'nodes': {
          
          }, 'links': {
          
          }}
        for s in net.switches:
            topo['nodes'][s.name] = {
          
          'agent': agent, 'ports': {
          
          }}
        path = '/sys/devices/virtual/net/'
        for child in listdir(path):
            parts = match('(^.+)-(.+)', child)
            if parts == None: continue
            if parts.group(1) in topo['nodes']:
                ifindex = open(path + child + '/ifindex').read().split('\n', 1)[0]
                topo['nodes'][parts.group(1)]['ports'][child] = {
          
          'ifindex': ifindex}
        i = 0
        for s1 in net.switches:
            j = 0
            for s2 in net.switches:
                if j > i:
                    intfs = s1.connectionsTo(s2)
                    for intf in intfs:
                        s1ifIdx = topo['nodes'][s1.name]['ports'][intf[0].name]['ifindex']
                        s2ifIdx = topo['nodes'][s2.name]['ports'][intf[1].name]['ifindex']
                        linkName = '%s-%s' % (s1.name, s2.name)
                        topo['links'][linkName] = {
          
          'node1': s1.name, 'port1': intf[0].name, 'node2': s2.name, 'port2': intf[1].name}
                j += 1
            i += 1
    
        opener = build_opener(HTTPHandler)
        request = Request('http://%s:8008/topology/json' % collector, data=dumps(topo).encode('utf-8')) # TODO
        request.add_header('Content-Type', 'application/json')
        request.get_method = lambda: 'PUT'
        url = opener.open(request)
    
      def result(*args, **kwargs):
          res = fn(*args, **kwargs)
          net = args[0]
          collector = environ.get('COLLECTOR', '127.0.0.1')  #! 环境变量
          sampling = environ.get('SAMPLING', '10')
          polling = environ.get('POLLING', '10')
          (ifname, agent) = getIfInfo(collector)
          configSFlow(net, collector, ifname, sampling, polling)
          sendTopology(net, agent, collector)
          return res
    
      return result
    
    
    setattr(Mininet, 'start', wrapper(Mininet.__dict__['start']))
    
    

Guess you like

Origin blog.csdn.net/Hesy_H/article/details/121525733