系统基础信息模块详解

系统基础信息采集模块作为监控模块的重要组成部分,能够帮助运维人员了解当前系统的健康程度,同时也是衡量业务的服务质量的依据,如果系统资源吃紧,会直接影响业务服务质量及用户体验。获取设备的更多信息,能让运维人员更好地评估带宽、设备资源是否应该扩容。

一. 系统信息采集:psutil

psutil 是一个跨平台的库,能够轻松获取系统运行的进程和系统利用率(cpu、内存、磁盘、网络等)信息。实现了同等命令行工具提供的功能,如:ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap等。支持linux、windows、freebsd等系统。

通过psutil模块获取服务的指标数据,包括基本性能、块设备、网卡、系统信息、网络地址等。这样可以全方位了解服务状态,同时可以结合告警机制,第一时间发现问题,并处理。

例如,我们可以使用命令来获取内存信息

  1. ##物理内存total值
  2. [root@localhost ~]# free -m | grep 'Mem' | awk '{print $2}'
  3. 3931
  4. ##物理内存used值
  5. [root@localhost ~]# free -m | grep 'Mem' | awk '{print $3}'
  6. 909

如果使用psutil库实现则更加简单明了。psutil大小单位一般都采用字节。

  1. In [1]: import psutil
  2. In [2]: mem = psutil.virtual_memory()
  3. In [3]: mem.total
  4. Out[3]: 4122857472
  5. In [4]: mem.used
  6. Out[4]: 927088640

1.1 psutil安装

地址: https://pypi.org/project/psutil/

或者:https://psutil.readthedocs.io/en/latest/

  1. ##使用pip3安装
  2. # pip3 install psutil
  3. ##使用yum安装
  4. # yum install python34-psutil
  5. ##使用源码安装
  6. ##下载psutil 源码;解压,并进入执行
  7. # python3 setup.py install

1.2 获取系统性能信息

采集系统基本性能信息包括CPU、内存、磁盘、网络等,可以完整描述当前系统的运行状态及质量。

CPU信息

  • 查看CPU的核数
    ``` In [5]: psutil.cpu_count()
    Out[5]: 4

In [6]: psutil.cpu_count(logical=True)
Out[6]: 4

查看cpu的核心数,默认logical=True,即超线程也算cpu的核心。

而平时所谓的双核是一颗cpu上有两个物理的cpu核。

  1. - 查看CPU时间

查看cpu时间使用情况,默认percpu=False,即不单独显示每个cpu而是汇总显示。

如果percpu=True 则会显示每个cpu使用情况。(单位为秒)

In [9]: psutil.cpu_times()
Out[9]: scputimes(user=59.93, nice=12.06, system=57.91, idle=25899.19, iowait=3.85, irq=0.0, softirq=2.69, steal=0.0, guest=0.0, guest_nice=0.0)

In [10]: psutil.cpu_times(percpu=True)
Out[10]: [scputimes(user=13.41, nice=1.68, system=14.27, idle=6485.1, iowait=1.45, irq=0.0, softirq=0.48, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=15.81, nice=5.04, system=16.89, idle=6474.79, iowait=1.34, irq=0.0, softirq=1.3, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=21.31, nice=1.5, system=13.1, idle=6483.19, iowait=0.35, irq=0.0, softirq=0.59, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=9.47, nice=3.82, system=13.67, idle=6490.25, iowait=0.71, irq=0.0, softirq=0.3, steal=0.0, guest=0.0, guest_nice=0.0)]

查看用户态使用时间

In [14]: psutil.cpu_times().user
Out[14]: 61.94

查看内核态使用时间

In [15]: psutil.cpu_times().system
Out[15]: 58.24

  1. - 查看CPU的利用率

计算cpu在一定时间内的利用率,这里并不是指cpu时间的利用率;

由于第一次运行没有参照计算的时间点,所以第一次计算的值会舍弃。

interval是指阻塞时间即统计的时间范围;

percpu是指不是不要显示每个cpu的情况。

In [16]: psutil.cpu_percent()
Out[16]: 0.2

In [17]: psutil.cpu_percent(interval=5,percpu=True)
Out[17]: [0.0, 0.0, 0.0, 0.0]

  1. - 查看CPU时间的利用率

这个命令是和cpu_times是一组的,一个显示使用时长,一个显示使用时间百分比。

interval是指阻塞时间即统计的时间范围;percpu是指是不是要显示每个cpu的情况。

In [2]: psutil.cpu_times_percent()
Out[2]: scputimes(user=0.3, nice=0.0, system=0.1, idle=99.6, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)

Out3: [scputimes(user=0.0, nice=0.0, system=0.0, idle=100.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=0.0, nice=0.0, system=0.0, idle=100.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=0.0, nice=0.0, system=0.0, idle=100.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0), scputimes(user=0.0, nice=0.0, system=0.0, idle=100.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)]

  1. - 查看上下文切换次数及中断次数

In [4]: psutil.cpu_stats()
Out[4]: scpustats(ctx_switches=199851, interrupts=137379, soft_interrupts=120317, syscalls=0)

  1. <a name="4d34eb9a"></a>
  2. #### 内存信息
  3. - 查看物理内存使用情况

查看内存使用情况,单位字节

In [5]: psutil.virtual_memory()
Out[5]: svmem(total=4122857472, available=3349499904, percent=18.8, used=529518592, free=3218681856, active=374730752, inactive=287744000, buffers=2166784, cached=372490240, shared=15130624, slab=86069248)

只查看总的内存使用情况

In [6]: psutil.virtual_memory().total
Out[6]: 4122857472

  1. - 查看虚拟内存使用情况

获取SWAP分区信息

In [7]: psutil.swap_memory()
Out[7]: sswap(total=4160745472, used=0, free=4160745472, percent=0.0, sin=0, sout=0)

In [8]: psutil.swap_memory().free
Out[8]: 4160745472

  1. <a name="9836563e"></a>
  2. #### 磁盘信息
  3. 对于磁盘,最关注的应该是磁盘利用率及IO信息。
  4. - 查看磁盘有哪些分区

默认参数all = False是指仅显示物理硬盘的分区挂载信息;

如果all = True还会显示一些虚拟的文件系统的挂载信息,如proc。

In [9]: psutil.disk_partitions()
Out[9]: [sdiskpart(device=’/dev/mapper/centos-root’, mountpoint=’/‘, fstype=’xfs’, opts=’rw,relatime,attr2,inode64,noquota’), sdiskpart(device=’/dev/sda1’, mountpoint=’/boot’, fstype=’xfs’, opts=’rw,relatime,attr2,inode64,noquota’)]

  1. - 查看磁盘使用情况

显示指定目录所在分区的磁盘使用情况,单位字节。

In [12]: psutil.disk_usage(“/“)
Out[12]: sdiskusage(total=48420556800, used=6443536384, free=41977020416, percent=13.3)

In [16]: psutil.disk_usage(“/boot”)
Out[16]: sdiskusage(total=1063256064, used=178417664, free=884838400, percent=16.8)


-  查看磁盘读写情况

显示磁盘的读写次数,读写字节数,及读写时间(毫秒)。

perdisk : 是否显示每个分区的读写情况

nowrap : 是否保持之前的记录,即数据是从开机时统计的,数值是累加的。保持默认即可。

In [17]: psutil.disk_io_counters()
Out[17]: sdiskio(read_count=18722, write_count=995, read_bytes=724747776, write_bytes=16294912, read_time=6189, write_time=748, read_merged_count=3, write_merged_count=51, busy_time=5038)

In [18]: psutil.disk_io_counters(perdisk=True)
Out[18]: {‘sr0’: sdiskio(read_count=18, write_count=0, read_bytes=1052672, write_bytes=0, read_time=25, write_time=0, read_merged_count=0, write_merged_count=0, busy_time=18), ‘sda’: sdiskio(read_count=10314, write_count=484, read_bytes=366857216, write_bytes=9240576, read_time=3200, write_time=356, read_merged_count=3, write_merged_count=51, busy_time=2615), ‘sda1’: sdiskio(read_count=1828, write_count=4, read_bytes=6259200, write_bytes=2097152, read_time=215, write_time=6, read_merged_count=0, write_merged_count=0, busy_time=209), ‘sda2’: sdiskio(read_count=8456, write_count=480, read_bytes=359016960, write_bytes=7143424, read_time=2981, write_time=350, read_merged_count=3, write_merged_count=51, busy_time=2421), ‘dm-0’: sdiskio(read_count=8302, write_count=531, read_bytes=354580992, write_bytes=7143424, read_time=2943, write_time=400, read_merged_count=0, write_merged_count=0, busy_time=2399), ‘dm-1’: sdiskio(read_count=88, write_count=0, read_bytes=2256896, write_bytes=0, read_time=21, write_time=0, read_merged_count=0, write_merged_count=0, busy_time=12)}


<a name="c53ecdae"></a>
#### 网络信息

-  查看网络流量信息

网卡流量统计,包括 发字节,收字节,发包数,收包数,收包错误数,发包错误数,丢包数。

pernic:是指是否要显示每一块网卡的流量信息

In [19]: psutil.net_io_counters()
Out[19]: snetio(bytes_sent=126828, bytes_recv=94292, packets_sent=876, packets_recv=1171, errin=0, errout=0, dropin=0, dropout=0)

In [20]: psutil.net_io_counters(pernic=True)
Out[20]: {‘lo’: snetio(bytes_sent=5920, bytes_recv=5920, packets_sent=68, packets_recv=68, errin=0, errout=0, dropin=0, dropout=0), ‘virbr0-nic’: snetio(bytes_sent=0, bytes_recv=0, packets_sent=0, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0), ‘virbr0’: snetio(bytes_sent=0, bytes_recv=0, packets_sent=0, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0), ‘ens33’: snetio(bytes_sent=124834, bytes_recv=91126, packets_sent=831, packets_recv=1139, errin=0, errout=0, dropin=0, dropout=0)}


-  查看网络连接信息 <br />kind可用的值

显示 文件描述符,协议簇,协议类型,本机地址,远程地址,tcp状态,pid

In [29]: psutil.net_connections(kind=”inet4”)
Out[29]: [sconn(fd=3, family=, type=, laddr=addr(ip=’192.168.154.150’, port=22), raddr=addr(ip=’192.168.154.1’, port=55946), status=’ESTABLISHED’, pid=2036), sconn(fd=12, family=, type=, laddr=addr(ip=’0.0.0.0’, port=5353), raddr=(), status=’NONE’, pid=865), sconn(fd=9, family=, type=, laddr=addr(ip=’127.0.0.1’, port=6010), raddr=(), status=’LISTEN’, pid=2036), sconn(fd=3, family=, type=, laddr=addr(ip=’0.0.0.0’, port=67), raddr=(), status=’NONE’, pid=1617), sconn(fd=10, family=, type=, laddr=addr(ip=’0.0.0.0’, port=616), raddr=(), status=’NONE’, pid=867), sconn(fd=12, family=, type=, laddr=addr(ip=’127.0.0.1’, port=631), raddr=(), status=’LISTEN’, pid=1335), sconn(fd=3, family=, type=, laddr=addr(ip=’0.0.0.0’, port=22), raddr=(), status=’LISTEN’, pid=1337), sconn(fd=13, family=, type=, laddr=addr(ip=’0.0.0.0’, port=48286), raddr=(), status=’NONE’, pid=865), sconn(fd=5, family=, type=, laddr=addr(ip=’127.0.0.1’, port=323), raddr=(), status=’NONE’, pid=904), sconn(fd=5, family=, type=, laddr=addr(ip=’192.168.122.1’, port=53), raddr=(), status=’NONE’, pid=1617), sconn(fd=6, family=, type=, laddr=addr(ip=’192.168.122.1’, port=53), raddr=(), status=’LISTEN’, pid=1617), sconn(fd=13, family=, type=, laddr=addr(ip=’127.0.0.1’, port=25), raddr=(), status=’LISTEN’, pid=1548), sconn(fd=4, family=, type=, laddr=addr(ip=’0.0.0.0’, port=111), raddr=(), status=’LISTEN’, pid=867), sconn(fd=5, family=, type=, laddr=addr(ip=’0.0.0.0’, port=111), raddr=(), status=’NONE’, pid=867)]

| Kind Value | Connections using |
| --- | --- |
| inet | IPv4 and IPv6 |
| inet4 | IPv4 |
| inet6 | IPv6 |
| tcp | TCP |
| tcp4 | TCP over IPv4 |
| tcp6 | TCP over IPv6 |
| udp | UDP |
| udp4 | UDP over IPv4 |
| udp6 | UDP over IPv6 |
| unix | UNIX socket (both UDP and TCP protocols) |
| all | the sum of all the possible families and protocols |

-  查看网卡地址

显示协议簇,IP地址,掩码,广播地址,ptp(是否为点到点网络和广播互斥)

In [30]: psutil.net_if_addrs()
Out[30]: {‘lo’: [snicaddr(family=, address=’127.0.0.1’, netmask=’255.0.0.0’, broadcast=None, ptp=None), snicaddr(family=, address=’::1’, netmask=’ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff’, broadcast=None, ptp=None), snicaddr(family=, address=’00:00:00:00:00:00’, netmask=None, broadcast=None, ptp=None)], ‘ens33’: [snicaddr(family=, address=’192.168.154.150’, netmask=’255.255.255.0’, broadcast=’192.168.154.255’, ptp=None), snicaddr(family=, address=’fe80::efa3:4c70:6600:c794%ens33’, netmask=’ffff:ffff:ffff:ffff::’, broadcast=None, ptp=None), snicaddr(family=, address=’00:0c:29:a9:5b:52’, netmask=None, broadcast=’ff:ff:ff:ff:ff:ff’, ptp=None)], ‘virbr0’: [snicaddr(family=, address=’192.168.122.1’, netmask=’255.255.255.0’, broadcast=’192.168.122.255’, ptp=None), snicaddr(family=, address=’52:54:00:60:15:78’, netmask=None, broadcast=’ff:ff:ff:ff:ff:ff’, ptp=None)], ‘virbr0-nic’: [snicaddr(family=, address=’52:54:00:60:15:78’, netmask=None, broadcast=’ff:ff:ff:ff:ff:ff’, ptp=None)]}


-  查看网卡状态

显示网卡信息: 是否开启, 双工模式, 速度, 最大传输单元

In [35]: psutil.net_if_stats()
Out[35]: {‘lo’: snicstats(isup=True, duplex=, speed=0, mtu=65536), ‘virbr0-nic’: snicstats(isup=False, duplex=, speed=10, mtu=1500), ‘virbr0’: snicstats(isup=True, duplex=, speed=0, mtu=1500), ‘ens33’: snicstats(isup=True, duplex=, speed=1000, mtu=1500)}


<a name="4bcd9f8e"></a>
#### 其他系统信息

-  查看开机时间

以Linux时间戳格式返回

In [36]: psutil.boot_time()
Out[36]: 1588253889.0

转换成自然时间格式

In [37]: import datetime

In [38]: datetime.datetime.fromtimestamp(psutil.boot_time()).strftime(“%Y-%m-%d %H:%M:%S”)
Out[38]: ‘2020-04-30 21:38:09’


-  获取当前登录用户信息

In [39]: psutil.users()
Out[39]: [suser(name=’root’, terminal=’pts/0’, host=’192.168.154.1’, started=1588253952.0, pid=2042)]


<a name="4572fe1c"></a>
### 1.3 系统进程管理方法

获得当前系统的进程信息,可以让运维人员得知应用程序的运行状态,包括进程的启动时间、查看或设置CPU亲和度、内存使用率、IO信息、socket连接、线程数等。

<a name="9a2a4b3b"></a>
#### 进程信息

psutil.pids()方法获取所有进程PID,psutil.Process()方法获取单个进程的名称、路径、状态、系统资源利用率等信息。

列出所有进程PID

In [42]: psutil.pids()
Out[42]: [1, 2, 4, ….略 2980, 3036]

查看pid 是不是存在

In [43]: psutil.pid_exists(1200)
Out[43]: False

实例化一个Process对象,参数为一个进程PID

In [59]: p = psutil.Process(3133)

进程名

In [60]: p.name()
Out[60]: ‘sshd’

进程bin路径

In [61]: p.exe()
Out[61]: ‘/usr/sbin/sshd’

进程工作目录绝对路径

In [62]: p.cwd()
Out[62]: ‘/‘

进程状态

In [63]: p.status()
Out[63]: ‘sleeping’

进程创建时间,时间戳格式

In [64]: p.create_time()
Out[64]: 1588260025.66

进程UID信息

In [65]: p.uids()
Out[65]: puids(real=0, effective=0, saved=0)

进程GID信息

In [66]: p.gids()
Out[66]: pgids(real=0, effective=0, saved=0)

进程CPU时间信息

In [67]: p.cpu_times()
Out[67]: pcputimes(user=0.02, system=0.01, children_user=0.0, children_system=0.0, iowait=0.0)

进程内存利用率

In [68]: p.memory_percent()
Out[68]: 0.1520033142683425

进程内存rss、vms信息

In [69]: p.memory_info()
Out[69]: pmem(rss=6266880, vms=167538688, shared=4841472, text=819200, lib=0, data=970752, dirty=0)

进程IO信息,包括读写IO数及字节数

In [70]: p.io_counters()
Out[70]: pio(read_count=513, write_count=92, read_bytes=0, write_bytes=0, read_chars=756132, write_chars=33958)

进程打开的socker连接列表

In [71]: p.connections()
Out[71]: [pconn(fd=3, family=, type=, laddr=addr(ip=’192.168.154.150’, port=22), raddr=addr(ip=’192.168.154.1’, port=58562), status=’ESTABLISHED’), pconn(fd=9, family=, type=, laddr=addr(ip=’127.0.0.1’, port=6011), raddr=(), status=’LISTEN’), pconn(fd=8, family=, type=, laddr=addr(ip=’::1’, port=6011), raddr=(), status=’LISTEN’)]

进程开启的线程数

In [72]: p.num_threads()
Out[72]: 1


<a name="68ef8e28"></a>
#### popen类的使用

psutil提供的popen类的作用是获取用户启动的应用程序进程信息,以便跟踪程序进程的运行状态。具体实现方法如下:

In [75]: import psutil

In [76]: from subprocess import PIPE

通过psutil的Popen方法启动的应用程序,可以跟踪该程序运行的所有相关信息

In [77]: p = psutil.Popen([“/usr/bin/python”,”-c”, “print(‘hello’)”], stdout=PIPE)

In [78]: p.name()
Out[78]: ‘python3’

In [79]: p.username()
Out[79]: ‘root’

In [80]: p.communicate()
Out[80]: (b’hello\n’, None)

In [84]: p.cpu_times()
Out[84]: pcputimes(user=0.0, system=0.0, children_user=0.0, children_system=0.0, iowait=0.0)

上小节讲的方法均可使用


<a name="561d073a"></a>
## 二. IP地址处理模块:IPy

IP地址规划是网络设计中非常重要的一个环节,Python提供了一个强大的第三方模块IPy,可以很好地辅助我们高效完成IP的规划工作。

官方地址:[https://github.com/autocracy/python-ipy](https://github.com/autocracy/python-ipy)

软件安装:

pip3 install IPy


<a name="951b28a2"></a>
### 2.1 IP地址、网段的基本处理

-  判断IP版本

In 3: IP(‘192.168.100.1’).version()
Out3: 4

In [4]: IP(‘2001::1’).version()
Out[4]: 6


-  输出IP清单

In [5]: from IPy import IP

In [6]: ip = IP(‘192.168.24.0/29’)

输出IP网段的个数

In [8]: print(ip.len())
8

输出网段的IP清单

In [9]: for x in ip: …: print(x) …:
192.168.24.0 192.168.24.1 192.168.24.2 192.168.24.3 192.168.24.4 192.168.24.5 192.168.24.6 192.168.24.7


-  IPy 常用方法

reverseNames : 将ip变为dns反向解析地址格式

iptype : 查看ip类型—公网地址、私网地址等

int : 将ip输出为十进制表示

strHex : 将ip输出为十六进制表示

strBin : 将ip输出为二进制表示

In [10]: from IPy import IP

In [11]: ip = IP(‘192.168.6.2’)

In [12]: ip.reverseNames()
Out[12]: [‘2.6.168.192.in-addr.arpa.’]

In [14]: ip.iptype()
Out[14]: ‘PRIVATE’

In [15]: ip.int()
Out[15]: 3232237058

In [16]: ip.strHex()
Out[16]: ‘0xc0a80602’

In [17]: ip.strBin()
Out[17]: ‘11000000101010000000011000000010’

netmask : 输出网络掩码地址

net : 输出网络地址

broadcast : 输出广播地址

In [21]: ip = IP(‘192.168.6.0/24’)

In [22]: ip.net()
Out[22]: IP(‘192.168.6.0’)

In [23]: ip.netmask()
Out[23]: IP(‘255.255.255.0’)

In [24]: ip.broadcast()
Out[24]: IP(‘192.168.6.255’)


-  比较网段

In [25]: IP(‘10.0.0.0/24’) < IP(‘12.0.0.0/24’)
Out[25]: True

判断IP地址和网段是否包含于另一个网段中

In [26]: ‘192.168.1.100’ in IP(‘192.168.1.0/24’)
Out[26]: True

In [27]: IP(‘192.168.1.0/24’) in IP(‘192.168.0.0/16’)
Out[27]: True

判断两个网段是否存在重叠,1为存在,0为不重叠

In [28]: IP(‘192.168.0.0/23’).overlaps(‘192.168.1.0/24’)
Out[28]: 1

In [29]: IP(‘192.168.2.0/24’).overlaps(‘192.168.1.0/24’)
Out[29]: 0


-  计算掩码、网络等

1、根据 ip 及子网掩码 求掩码位数

2、根据ip范围,求掩码位数

3、根据掩码位数,求子网掩码

In [30]: IP(‘192.168.6.2’).make_net(‘255.255.0.0’)
Out[30]: IP(‘192.168.0.0/16’)

In [31]: IP(‘192.168.6.2/255.255.255.0’,make_net=True)
Out[31]: IP(‘192.168.6.0/24’)

In [32]: IP(‘192.168.6.2/255.255.240.0’,make_net=True)
Out[32]: IP(‘192.168.0.0/20’)

In [33]: IP(‘192.168.6.0-192.168.6.255’,make_net=True)
Out[33]: IP(‘192.168.6.0/24’)

In [35]: IP(‘192.168.6.0-192.168.6.127’,make_net=True)
Out[35]: IP(‘192.168.6.0/25’)

In [37]: IP(‘192.168.6.0-192.168.6.63’,make_net=True)
Out[37]: IP(‘192.168.6.0/26’)


-  strNormal 可以输出ip格式 
   - 参数 0: 使用prefix格式(192.168.6.0/24)时,主机部分必须全部为 0 . 返回网络地址
   - 参数1 : 输出prefix格式的ip表示
   - 参数2 : 输出 decimalnetwork(192.168.6.0/255.255.255.0)格式的ip表示
   - 参数3 : 输出ip的范围

In [38]: IP(‘192.168.100.0/24’).strNormal(0)
Out[38]: ‘192.168.100.0’

In [39]: IP(‘192.168.100.0/24’).strNormal(1)
Out[39]: ‘192.168.100.0/24’

In [40]: IP(‘192.168.100.0/24’).strNormal(2)
Out[40]: ‘192.168.100.0/255.255.255.0’

In [41]: IP(‘192.168.100.0/24’).strNormal(3)
Out[41]: ‘192.168.100.0-192.168.100.255’


<a name="2a8b54b4"></a>
### 2.2 案例

根据输入的IP或者子网返回网络、掩码、广播、反向解析、子网数、IP类型等信息。

!/usr/bin/python3

from IPy import IP

ip_s = input(‘please input an IP or net-range: ‘)

ips = IP(ip_s)

if len(ips) > 1: ##为一个网络地址 print(‘net: {}’.format(ips.net()) ) ##输出网络地址 print(‘netmask: {}’.format(ips.netmask())) ##输出网络掩码 print(‘broadcast: {}’.format(ips.broadcast())) ##输出广播地址 print(‘reverse address: {}’.format(ips.reverseNames()[0])) ##输出地址反向域名 print(‘subnet: {}’.format(len(ips))) ##输出网络子网个数 else: print(‘reverse address: {}’.format(ips.reverseNames()[0]))

print(‘hexadecimal: {}’.format(ips.strHex())) ##输出十六进制地址 print(‘binary ip: {}’.format(ips.strBin())) ##输出二进制地址 print(‘iptype: {}’.format(ips.iptype())) ##输出地址类型,私网地址还是公网地址


<a name="b7e09f5e"></a>
## 三. DNS处理模块 dnspython

dnspython 是Python实现的一个DNS工具包,它支持几乎所有的记录类型。可以用于查询、传输并动态更新Zone信息,同时支持TSIG(事务签名)验证消息等。可以利用查询功能来实现dns服务监控以及解析结果的校验,可以代替nslookup 、dig 等工具。

官网:[http://www.dnspython.org/](http://www.dnspython.org/)

安装:`pip3 install dnspython`

<a name="a488929c"></a>
### 3.1 模块域名解析方法详解

dnspython模块提供了大量的DNS处理方法,最常用的方法是域名查询。dnspython提供了一个DNS解析器类–resolver,使用它的query方法来实现域名的查询功能。query方法的定义如下:

query(qname, rdtype=1, rdclass=1, tcp=False, source=None, raise_on_no_answer=True, source_port=0, lifetime=None)


- qname参数为查询的域名
- rdtype参数用来指定RR资源的类型,常用的类型如下: 
   - A记录,将主机名转换成IP地址
   - MX记录,邮件交换记录,定义邮件服务器的域名
   - CNAME记录,指别名记录,实现域名间的映射
   - NS记录,标记区域的域名服务器及授权子域
   - PTR记录,反向解析,与A记录相反,将IP转换成主机名
   - SOA记录,SOA标记,一个起始授权区的定义
- rdclass参数用于指定网络类型,可选的值有IN、CH与HS,其中IN为默认,使用最广泛
- tcp参数用于指定查询是否启用TCP协议,默认为False(不启用)
- source参数指定查询源ip地址
- source_port参数指定查询源端口
- raise_on_no_answer参数指定当查询无响应时是否触发异常,默认为True。

**查询后常用方法**:

- qname :查询的域名
- rdclass :查询的网络类型
- rdtype :查询的dns类型
- response :查询结果

```bash
In [1]: import dns.resolver                                                                                                                  

## 查询www.jd.com的A记录
In [2]: ret = dns.resolver.query('www.jd.com','A')                                                                                           

In [3]: ret.qname                                                                                                                            
Out[3]: <DNS name www.jd.com.>

In [4]: ret.rdclass                                                                                                                          
Out[4]: 1

In [5]: ret.rdtype                                                                                                                           
Out[5]: 1

In [6]: ret.response.answer                                                                                                                  
Out[6]: 
[<DNS www.jd.com. IN CNAME RRset>,
 <DNS www.jd.com.gslb.qianxun.com. IN CNAME RRset>,
 <DNS www.jdcdn.com. IN CNAME RRset>,
 <DNS img20.360buyimg.com.s.galileo.jcloud-cdn.com. IN CNAME RRset>,
 <DNS img2x-sched.jcloud-cdn.com. IN A RRset>]

In [7]: for i in ret: 
   ...:     print(i) 
   ...:                                                                                                                                      
124.236.40.3

##查询baidu.com的NS记录
In [8]: ret2 = dns.resolver.query('baidu.com','NS')                                                                                          

In [9]: for i in ret2: 
   ...:     print(i) 
   ...:                                                                                                                                      
ns2.baidu.com.
ns3.baidu.com.
dns.baidu.com.
ns4.baidu.com.
ns7.baidu.com.

##查询腾讯的邮箱服务器MX记录
In [10]: ret3 = dns.resolver.query('qq.com','MX')                                                                                            

In [11]: for i in ret3: 
    ...:     print(i) 
    ...:                                                                                                                                     
30 mx1.qq.com.
20 mx2.qq.com.
10 mx3.qq.com.

In [12]: for i in ret3: 
    ...:     print('MX preference = {} mail exchanger = {}'.format(i.preference,i.exchange)) 
    ...:      
    ...:                                                                                                                                     
MX preference = 30 mail exchanger = mx1.qq.com.
MX preference = 20 mail exchanger = mx2.qq.com.
MX preference = 10 mail exchanger = mx3.qq.com.