Материал содержит описание функций модуля psutil
с примерами, которые возвращают информацию о сетевых картах и их соединениях, такую как: статистику сетевого ввода-вывода, соединения сокетов, адреса сетевых карт.
psutil.net_io_counters()
общесистемная статистика сетевого ввода-вывода,psutil.net_connections()
общесистемные соединения сокетов,psutil.net_if_addrs()
адреса, связанные с каждой сетевой картой,psutil.net_if_stats()
информацию о каждой сетевой карте,psutil.net_io_counters(pernic=False, nowrap=True)
:Функция psutil.net_io_counters()
возвращает общесистемную статистику сетевого ввода-вывода в виде именованного кортежа, включающего следующие атрибуты:
bytes_sent
: количество отправленных байтов;bytes_recv
: количество полученных байтов;packets_sent
: количество отправленных пакетов;packets_recv
: количество полученных пакетов;errin
: общее количество ошибок при получении;errout
: общее количество ошибок при отправке;dropin
: общее количество входящих пакетов, которые были отброшены;dropout
: общее количество исходящих пакетов, которые были отброшены (всегда 0 на macOS и BSD).Если pernic
равно True
, то возвращает ту же информацию для каждого сетевого интерфейса, установленного в системе, в виде словаря с именами сетевых интерфейсов в качестве ключей и именованным кортежем, в качестве значений описанных выше.
Пример использования psutil.net_io_counters()
:
>>> import psutil >>> psutil.net_io_counters() # snetio(bytes_sent=14508483, bytes_recv=62749361, packets_sent=84311, # packets_recv=94888, errin=0, errout=0, dropin=0, dropout=0) >>> psutil.net_io_counters(pernic=True) # { # 'lo': snetio(bytes_sent=547971, bytes_recv=547971, packets_sent=5075, # packets_recv=5075, errin=0, errout=0, dropin=0, dropout=0), # 'wlan0': snetio(bytes_sent=13921765, bytes_recv=62162574, packets_sent=79097, # packets_recv=89648, errin=0, errout=0, dropin=0, dropout=0) #}
В некоторых системах, таких как Linux, в очень загруженных или долгоживущих системах числа, возвращаемые ядром, могут переполняться и переноситься (перезапускаться с нуля). Если nowrap
имеет значение True
, то модуль psutil
обнаружит и скорректирует эти числа при вызовах функций и добавит "старое значение" к "новому значению", чтобы возвращаемые числа всегда увеличивались или оставались неизменными, но никогда не уменьшались. Для аннулирования кеша nowrap
можно использовать метод psutil.net_io_counters.cache_clear()
. На машинах без сетевых интерфейсов эта функция вернет None или {}, если pernic имеет значение True.
psutil.net_connections(kind='inet')
:Функция psutil.net_connections()
возвращает общесистемные соединения сокетов в виде списка именованных кортежей. Каждый именованный кортеж предоставляет 7 атрибутов:
fd
: дескриптор файла сокета. Если соединение относится к текущему процессу, это может быть передано socket.fromfd()
для получения пригодного для использования объекта сокета. В Windows и SunOS это значение всегда равно -1.family
: семейство адресов, либо AF_INET
, AF_INET6
, либо AF_UNIX
.type
: тип адреса: SOCK_STREAM
, SOCK_DGRAM
или SOCK_SEQPACKET
.laddr
: локальный адрес в виде (ip, port)
, именованный кортеж или путь path
в случае сокетов AF_UNIX. Для сокетов UNIX смотрите примечания ниже.raddr
: удаленный адрес в виде (ip, port)
, именованный кортеж или абсолютный путь path
в случае сокетов UNIX. Когда удаленная конечная точка не подключена, то возвращается пустой кортеж (AF_INET*)
или ''
(AF_UNIX). Для сокетов UNIX смотрите примечания ниже.status
: представляет состояние TCP-соединения. Возвращаемое значение является одной из констант psutil.CONN_*
(строка). Для сокетов UDP и UNIX это всегда будет psutil.CONN_NONE
.pid
: PID процесса, открывшего сокет, если его можно получить, иначе None
. На некоторых платформах (например, Linux) доступность этого поля меняется в зависимости от привилегий процесса (необходим root
доступ).Аргумент kind
представляет собой строку, которая фильтрует соединения, соответствующие следующим критериям.
Аргумент kind | Соединения с использованием |
"inet" | IPv4 и IPv6 |
"inet4" | IPv4 |
"inet6" | IPv6 |
"tcp" | TCP |
"tcp4" | TCP поверх IPv4 |
"tcp6" | TCP поверх IPv6 |
"udp" | UDP |
"udp4" | UDP поверх IPv4 |
"udp6" | UDP поверх IPv6 |
"unix" | Сокет UNIX (как протоколы UDP, так и TCP) |
"all" | сумма всех возможных семейств и протоколов |
В macOS и AIX для этой функции требуются привилегии root
. Чтобы получить соединения для каждого процесса, необходимо использовать объект Process.connections()
.
Пример использования psutil.net_connections()
:
>>> import psutil >>> psutil.net_connections() # [ # pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, # laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), # status='ESTABLISHED', pid=1254), # pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, # laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), # status='CLOSING', pid=2987), # pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, # laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), # status='ESTABLISHED', pid=None), # pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, # laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), # status='SYN_SENT', pid=None) # ...]
Примечание:
- (macOS и AIX) всегда вызывается
psutil.AccessDenied
, если только он не запущен от имени пользователяroot
. Это ограничение ОС, и утилитаlsof
делает то же самое.- (Solaris) Сокеты UNIX не поддерживаются.
- (Linux, FreeBSD) Поле
raddr
для сокетов UNIX всегда имеет значение''
. Это ограничение операционной системы.- (OpenBSD) Поля
laddr
иraddr
для сокетов UNIX всегда имеют значение''
. Это ограничение операционной системы.
psutil.net_if_addrs()
:Функция psutil.net_if_addrs()
возвращает адреса, связанные с каждой сетевой картой, установленной в системе, в виде словаря, ключами которого являются имена сетевых карт, а значением - список именованных кортежей для каждого адреса, назначенного сетевой карте. Каждый именованный кортеж включает в себя 5 полей:
family
: семейство адресов, либо AF_INET
, либо AF_INET6
, либо psutil.AF_LINK
, который ссылается на MAC-адрес.address
: адрес основной сетевой карты (устанавливается всегда).netmask
: адрес сетевой маски (может отсутствовать).broadcast
: широковещательный адрес (может быть None
).ptp
: расшифровывается как "точка-точка". Это адрес назначения в интерфейсе (обычно VPN). Широковещательная передача и ptp
являются взаимоисключающими. Может быть или нет.Пример использования psutil.net_if_addrs()
:
>>> import psutil >>> psutil.net_if_addrs() # { # 'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', # broadcast='127.0.0.1', ptp=None), snicaddr(family=<AddressFamily.AF_INET6: 10>, # address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, # ptp=None), snicaddr(family=<AddressFamily.AF_LINK: 17>, # address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)], # 'wlan0': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', # broadcast='192.168.1.255', ptp=None), snicaddr(family=<AddressFamily.AF_INET6: 10>, # address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, # ptp=None), snicaddr(family=<AddressFamily.AF_LINK: 17> , # address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)] # }
Примечания:
- если интересуют другие семейства адресов (например,
AF_BLUETOOTH
), то можно использовать более мощный сторонний модульnetifaces
.- можно иметь более одного адреса одного и того же семейства, связанного с каждым интерфейсом (поэтому значения
dict
представляют собой списки).- широковещательная передача и
ptp
не поддерживаются в Windows и всегда имеют значениеNone
.
psutil.net_if_stats()
:Функция psutil.net_if_stats()
возвращает информацию о каждой сетевой карте (интерфейсной плате), установленной в системе, в виде словаря, ключами которого являются имена сетевых карт, а значением - именованный кортеж со следующими полями:
isup
: логическое значение, указывающее, запущена ли сетевая карта (имеется в виду подключение кабеля Ethernet или Wi-Fi).duplex
: дуплексный тип связи; это может быть psutil.NIC_DUPLEX_FULL
, psutil.NIC_DUPLEX_HALF
или psutil.NIC_DUPLEX_UNKNOWN
.speed
: скорость сетевого адаптера, выраженная в мегабитах (МБ), если ее невозможно определить (например, ‘localhost’
), то будет установлена в 0.mtu
: максимальная единица передачи сетевого адаптера, выраженная в байтах..flags
: флаги интерфейса - строка разделенных запятыми (может быть пустой строкой). Возможные флаги: up
, broadcast
, debug
, loopback
, pointopoint
, notrailers
, running
, noarp
, promisc
, allmulti
, master
, slave
, multicast
, portsel
, dynamic
, oactive
, simplex
, link0
, link1
, link2
, и d2
(некоторые флаги доступны только на определенных платформах).Доступность: UNIX
Пример использования psutil.net_if_stats()
:
>>> import psutil >>> psutil.net_if_stats() # { # 'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, # speed=100, mtu=1500, flags='up,broadcast,running,multicast'), # 'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, # speed=0, mtu=65536, flags='up,loopback,running') # }
Этот пример представляет собой клон Linux утилиты ifconfig
:
import socket import psutil from psutil._common import bytes2human af_map = { socket.AF_INET: 'IPv4', socket.AF_INET6: 'IPv6', psutil.AF_LINK: 'MAC', } duplex_map = { psutil.NIC_DUPLEX_FULL: "full", psutil.NIC_DUPLEX_HALF: "half", psutil.NIC_DUPLEX_UNKNOWN: "?", } def main(): stats = psutil.net_if_stats() io_counters = psutil.net_io_counters(pernic=True) for nic, addrs in psutil.net_if_addrs().items(): print("%s:" % (nic)) if nic in stats: st = stats[nic] print(" stats : ", end='') print("speed=%sMB, duplex=%s, mtu=%s, up=%s" % ( st.speed, duplex_map[st.duplex], st.mtu, "yes" if st.isup else "no")) if nic in io_counters: io = io_counters[nic] print(" incoming : ", end='') print("bytes=%s, pkts=%s, errs=%s, drops=%s" % ( bytes2human(io.bytes_recv), io.packets_recv, io.errin, io.dropin)) print(" outgoing : ", end='') print("bytes=%s, pkts=%s, errs=%s, drops=%s" % ( bytes2human(io.bytes_sent), io.packets_sent, io.errout, io.dropout)) for addr in addrs: print(" %-4s" % af_map.get(addr.family, addr.family), end="") print(" address : %s" % addr.address) if addr.broadcast: print(" broadcast : %s" % addr.broadcast) if addr.netmask: print(" netmask : %s" % addr.netmask) if addr.ptp: print(" p2p : %s" % addr.ptp) print("") if __name__ == '__main__': main()
Вывод сценария:
$ python3 test.py lo: stats : speed=0MB, duplex=?, mtu=65536, up=yes incoming : bytes=1.95M, pkts=22158, errs=0, drops=0 outgoing : bytes=1.95M, pkts=22158, errs=0, drops=0 IPv4 address : 127.0.0.1 netmask : 255.0.0.0 IPv6 address : ::1 netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff MAC address : 00:00:00:00:00:00 docker0: stats : speed=0MB, duplex=?, mtu=1500, up=yes incoming : bytes=3.48M, pkts=65470, errs=0, drops=0 outgoing : bytes=164.06M, pkts=112993, errs=0, drops=0 IPv4 address : 172.17.0.1 broadcast : 172.17.0.1 netmask : 255.255.0.0 IPv6 address : fe80::42:27ff:fe5e:799e%docker0 netmask : ffff:ffff:ffff:ffff:: MAC address : 02:42:27:5e:79:9e broadcast : ff:ff:ff:ff:ff:ff wlp3s0: stats : speed=0MB, duplex=?, mtu=1500, up=yes incoming : bytes=7.04G, pkts=5637208, errs=0, drops=0 outgoing : bytes=372.01M, pkts=3200026, errs=0, drops=0 IPv4 address : 10.0.0.2 broadcast : 10.255.255.255 netmask : 255.0.0.0 IPv6 address : fe80::ecb3:1584:5d17:937%wlp3s0 netmask : ffff:ffff:ffff:ffff:: MAC address : 48:45:20:59:a4:0c broadcast : ff:ff:ff:ff:ff:ff
import sys import time try: import curses except ImportError: sys.exit('платформа не поддерживается') import psutil from psutil._common import bytes2human lineno = 0 win = curses.initscr() def printl(line, highlight=False): """Тонкая обертка вокруг модуля curses.""" global lineno try: if highlight: line += " " * (win.getmaxyx()[1] - len(line)) win.addstr(lineno, 0, line, curses.A_REVERSE) else: win.addstr(lineno, 0, line, 0) except curses.error: lineno = 0 win.refresh() raise else: lineno += 1 def poll(interval): """Необработанная статистика в интервале `interval`.""" tot_before = psutil.net_io_counters() pnic_before = psutil.net_io_counters(pernic=True) # спим в течении `interval` time.sleep(interval) tot_after = psutil.net_io_counters() pnic_after = psutil.net_io_counters(pernic=True) return (tot_before, tot_after, pnic_before, pnic_after) def refresh_window(tot_before, tot_after, pnic_before, pnic_after): """Вывод статистики на экран.""" global lineno # всего printl("total bytes: sent: %-10s received: %s" % ( bytes2human(tot_after.bytes_sent), bytes2human(tot_after.bytes_recv)) ) printl("total packets: sent: %-10s received: %s" % ( tot_after.packets_sent, tot_after.packets_recv)) # сведения об интерфейсе для каждой сети: # отсортируем сетевые интерфейсы, первыми # будут те, которые генерировали больше трафика. printl("") nic_names = list(pnic_after.keys()) nic_names.sort(key=lambda x: sum(pnic_after[x]), reverse=True) for name in nic_names: stats_before = pnic_before[name] stats_after = pnic_after[name] templ = "%-15s %15s %15s" printl(templ % (name, "TOTAL", "PER-SEC"), highlight=True) printl(templ % ( "bytes-sent", bytes2human(stats_after.bytes_sent), bytes2human( stats_after.bytes_sent - stats_before.bytes_sent) + '/s', )) printl(templ % ( "bytes-recv", bytes2human(stats_after.bytes_recv), bytes2human( stats_after.bytes_recv - stats_before.bytes_recv) + '/s', )) printl(templ % ( "pkts-sent", stats_after.packets_sent, stats_after.packets_sent - stats_before.packets_sent, )) printl(templ % ( "pkts-recv", stats_after.packets_recv, stats_after.packets_recv - stats_before.packets_recv, )) printl("") win.refresh() lineno = 0 def setup(): curses.start_color() curses.use_default_colors() for i in range(0, curses.COLORS): curses.init_pair(i + 1, i, -1) curses.endwin() win.nodelay(1) def tear_down(): win.keypad(0) curses.nocbreak() curses.echo() curses.endwin() if __name__ == '__main__': setup() try: interval = 0 while True: if win.getch() == ord('q'): break args = poll(interval) refresh_window(*args) interval = 0.5 except (KeyboardInterrupt, SystemExit): pass finally: tear_down()
Вывод сценария:
$ python3 test.py ----------------------------------------------------------- total bytes: sent: 1.49 G received: 4.82 G total packets: sent: 7338724 received: 8082712 wlan0 TOTAL PER-SEC ----------------------------------------------------------- bytes-sent 1.29 G 0.00 B/s bytes-recv 3.48 G 0.00 B/s pkts-sent 7221782 0 pkts-recv 6753724 0 eth1 TOTAL PER-SEC ----------------------------------------------------------- bytes-sent 131.77 M 0.00 B/s bytes-recv 1.28 G 0.00 B/s pkts-sent 0 0 pkts-recv 1214470 0