作為后端開發,特別是網絡游戲后端開發,經常需要處理各種現網問題,其中有不少是網絡相關的。
下面列舉的工具主要是在 linux 下的,診斷線上服務器問題的時候,往往是分秒必爭,所以這些工具都要用得很熟練,才能不耽誤事。
1. 工具
1.1 netstat
netstat 可以說是最常用的網絡工具了,它的作用就是查看網絡狀態,tcp、udp、unix socket 都可以。一般是結合 grep 命令來篩選結果。具體如何使用,可以 man 一下: man netstat
。
linux 下的基礎語法是:
usage: netstat [-vWeenNcCF] [<Af>] -r netstat {-V|--version|-h|--help}netstat [-vWnNcaeol] [<Socket> ...]netstat { [-vWeenNac] -i | [-cnNe] -M | -s [-6tuw] }-n, --numeric don't resolve names-l, --listening display listening server sockets-a, --all display all sockets (default: connected)-p, --programs display PID/Program name for sockets <Socket>={-t|--tcp} {-u|--udp} {-U|--udplite} {-S|--sctp} {-w|--raw}{-x|--unix} --ax25 --ipx --netrom<AF>=Use '-6|-4' or '-A <af>' or '--<af>'; default: inet
經常會用的選項:
-a
指定所有類型的連接,-t
指定 tcp 連接,-u
指定 udp 連接。-n
禁用解析,這個選項通常要帶上,否則會把 ip 地址解析成主機名,反而看不到什么有用的-p
顯示進程信息,這個選項通常也要帶上-l
只顯示 listen 的信息,如果只能查看監聽信息,就用這個
linux 例子:
命令 | 作用 |
---|---|
netstat -anp | grep 80 | 查看端口號為 80 的所有連接信息 |
netstat -tnp | grep 80 | 查看端口號為 80 的 tcp 連接信息 |
netstat -l | 查看所有的 listen |
netstat 在 windows 下也有相應的實現,不過命令參數與 linux 下略有不同,而且過濾結果也不能使用 grep,得使用 find。
windows 例子:
命令 | 作用 |
---|---|
netstat -ano | find "80" | 查看端口號為 80 的所有連接信息 |
netstat -ano | find "LISTEN" | 查看所有的 listen |
1.2 lsof
lsof 意為 list open files,可以顯示被打開的文件以及打開這些文件的進程。unix 一切皆文件,socket 也是文件,所以通過顯示文件信息,足以窺探系統的一些運行狀態。
如果足夠熟練,lsof 可以替代 netstat 和 ps 這兩個工具。
1.2.1 lsof 基本要點
-
沒有任何選項時,lsof 會列出所有活躍進程的所有打開文件。
-
有多個選項,默認執行 “或” 運算,比如同時傳遞 -i (獲取網絡信息) -p (獲取進程信息),會獲得兩者的結果。
-
使用 -a 可以對結果進行 “與” 運算。
關于 “或” 和 “與”,舉個例子,想要獲得進程 pid 為 191812 的 tcp 連接信息,需要這樣寫:lsof -p 191812 -i tcp -a
,不能只寫成 lsof -p 191812 -i tcp
。如果沒加 ‘-a’,結果將變成進程 pid 為 191812 的所有打開文件以及所有 tcp 連接信息的總和。
1.2.2 lsof 獲取網絡信息
先列舉一些網絡相關的用法,基礎語法是:
lsof -i [46][protocol][@hostname|hostaddr][:service|port]
要注意,這串東西 [46][protocol][@hostname|hostaddr][:service|port]
是根據需要填的,但要挨在一起,中間不要有空格。 比如 4tcp:9999
或者 tcp@127.0.0.1
或者 4tcp@127.0.0.1:9999
。
一些例子:
命令 | 作用 |
---|---|
lsof -i | 顯示所有網絡連接 |
lsof -i 6 | 僅顯示 ipv6 連接 |
lsof -i tcp | 僅顯示所有 tcp 連接 |
lsof -i udp | 僅顯示所有 udp 連接 |
lsof -i :9999 | 顯示端口為 9999 的連接 |
lsof -i :1000,2000 | 顯示端口號為 1000 或 2000 的連接 |
lsof -i :1000-9999 | 顯示端口范圍從 1000 到 9999 的連接 |
lsof -i 4tcp@127.0.0.1:9999 | 顯示ipv4,tcp協議,連接信息為 127.0.0.1 9999 的連接 |
lsof -i -s tcp:established | 顯示已經建立的 tcp 連接 |
lsof -i -s tcp:listen | 顯示等待連接 (listen) 的 tcp 端口 |
1.2.3 lsof 文件和目錄
查看正在使用指定文件和目錄的用戶或進程。
lsof 文件路徑
可以找出打開這個文件的資源信息,比如 lsof /root/a.txt
。
特別的,如果是用 vim 打開了文件,比如:root/a.txt,則通過 lsof /root/.a.txt.swp
可以找出來。通過 a.txt 是找不到的,因為 vim 打開的是一個 .swp 后綴的臨時文件。
1.2.4 lsof 命令、進程、用戶
通過 -c
選項可以找出使用指定命令的進程,比如:lsof -c 'sshd'
找出命令為 sshd 的進程打開的所有文件。
如果要配合其實工具使用,可以指定 -t
選項,只打印進程 id 出來。
通過 -p
選項可以找出指定 pid 的進程,比如 lsof -p 2341
找出 pid 為 2341 的進程打開的所有文件。
通過 -u
選項可以找出指定用戶打開的文件,比如 lsof -u root
可以找出 root 用戶打開的所有文件。
1.2.5 lsof 各列的意義
各列的意義[2],如下:
COMMAND:進程的名稱PID:進程標識符PPID:父進程標識符(需要指定-R參數)USER:進程所有者PGID:進程所屬組FD:文件描述符,應用程序通過文件描述符識別該文件。如 cwd、txt 等TYPE:文件類型,如DIR、REG等,常見的文件類型REG :常規文件,即普通文件DIR :目錄CHR :字符類型BLK :塊設備類型UNIX:UNIX 域套接字FIFO:先進先出 (FIFO) 隊列IPv4:網際協議 (IP) 套接字DEVICE:指定磁盤的名稱SIZE:文件的大小NODE:索引節點(文件在磁盤上的標識)NAME:打開文件的確切名稱
FD 的詳細信息[2][3],如下:
數字:文件的描述符 id,其中有3個是特別的:0 表示標準輸出,1 表示標準輸入,2 表示標準錯誤
cwd :current work dirctory,即應用程序的當前工作目錄
txt :program text (code and data),即程序代碼
lnn :library references (AIX)
er :FD information error (see NAME column)
jld :jail directory (FreeBSD)
ltx :shared library text (code and data)
mxx :hex memory-mapped type number xx
m86 :DOS Merge mapped file
mem :memory-mapped file
mmap:memory-mapped device
pd :parent directory
rtd :root directory
tr :kernel trace file (OpenBSD)
v86 :VP/ix mapped file一般在標準輸出、標準錯誤、標準輸入后還跟著文件狀態模式:r、w、u等,如下: u :表示該文件被打開并處于讀取/寫入模式
r :表示該文件被打開并處于只讀模式
w :表示該文件被打開并處于
space:表示該文件的狀態模式為unknow,且沒有鎖定
- :表示該文件的狀態模式為unknow,且被鎖定同時在文件狀態模式后面,還跟著相關的鎖,如下: N :for a Solaris NFS lock of unknown type;
r :for read lock on part of the file;
R :for a read lock on the entire file;
w :for a write lock on part of the file;(文件的部分寫鎖)
W :for a write lock on the entire file;(整個文件的寫鎖)
u :for a read and write lock of any length;
U :for a lock of unknown type;
x :for an SCO OpenServer Xenix lock on part of the file;
X :for an SCO OpenServer Xenix lock on the entire file;
space:if there is no lock.
1.3 nc
nc 即 netcat,nc 太有用了,它支持 tcp、udp,它可以作為客戶端,也可以作為服務端,非常全能。下面舉一些使用場景。
一、測試端口是否可以連通
這應該是使用最頻繁的用途了。
nc -v 127.0.0.1 9999
-v 可以打印出連接的詳情。
連接得上是類似這樣提示:“Connection to 127.0.0.1 9999 port [tcp/*] succeeded!”。
連接不上是這樣提示:“nc: connect to 127.0.0.1 port 9999 (tcp) failed: Connection refused”。
如果是 udp,則加上 -u 參數:
nc -uv 127.0.0.1 9999
二、監聽特定端口
nc -l 9999
這個的意義在于,有時候我們自己的服務端進程無法被遠端的客戶端連通,需要排除是我們的服務端進程邏輯有問題,還是物理機的網絡端口由于硬件或防火墻之類的問題無法連通。
如果是 udp,則加上 -u 參數:
nc -lu 9999
三、傳輸文件
nc 甚至可以拿來傳輸文件。
接收端:
nc -l 9999 > recv.txt
發送端:
nc 127.0.0.1 9999 < send.txt
2. 工具的數據來源
2.1 netstat、nstat、ifconfig、ethtool
數據來源[1]:
netstat、nstat 是來自 /proc/net/netstat 和 /proc/net/snmp 的數據;
ifconfig 是讀取 /proc/net/dev 下的數據,而后者的數據是從設備在內核的數據結構 net_device 里的結構 rtnl_link_stats64 中獲取的;
ethtool 是直接通過 ioctl 下放的方式從同樣的結構(net_device 中的 rtnl_link_stats64 )中獲取數據;
因此可以認為 ifconfig 和 ethtool 兩者看到的網卡相關數據來源是一樣的,但是 /proc/net/dev 進行了一定程度的歸檔,因此 ifconfig 中的 RX dropped = rx_dropped + rx_missed_errors,RX errors = rx_errors。
3. 參考
[1] johnazhang. 關于以ethtool為主的網絡指標統計工具之間統計數據關系的研究原創. Available at https://cloud.tencent.com/developer/article/2050526, 2022-07-18.
[2] 琦彥. lsof:獲取網絡信息、用戶操作、進程信息、文件信息. Available at https://blog.csdn.net/fly910905/article/details/88551497, 2019-03-14.
[3] man7. lsof. Available at https://man7.org/linux/man-pages/man8/lsof.8.html.