Статистика сетевых соединений и сетевого ввода-вывода в Python.
Содержание:
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