监控网络状态
监控网络状态
netstat network statistics
Linux netstat 命令用于显示网络状态。
利用 netstat
指令可让你得知整个 Linux 系统的网络情况。
netstat
命令很简单,也很直接,用于显示与 IP、TCP、UDP 和 ICMP 协议相关的统计数据,一般用于检验本机各端口的网络连接情况。netstat
是在内核中访问网络及相关信息的程序,它能提供 TCP 连接,TCP 和 UDP 监听,进程内存管理的相关报告。
netstat [-acCeFghilMnNoprstuvVwx][-A<网络类型>][--ip]
参数
-
-a
(all):显示所有选项,不使用-a
选项的时候(即默认情况)不显示 LISTEN 相关 -
-t
(tcp):仅显示 tcp 相关选项 -
-u
(udp):仅显示 udp 相关选项 -
-n
:拒绝显示别名,能显示数字的全部转化成数字。这样的好处是可以直接看到 IP 而不是域名,方便进行二次搜索 -
-l
:仅列出有在 Listen (监听) 的服務状态 -
-p
:显示建立相关链接的进程 ID 和程序名,注意,这个参数,需要 root 权限才能看到所有 -
-r
:显示路由信息,路由表 -
-e
:显示扩展信息,例如 uid 等 -
-s
:按各个协议进行统计 -
-c
:每隔一个固定时间,执行该netstat
命令。
提示:LISTEN 和 LISTENING 的状态只有用 -a
或者 -l
才能看到
常用 -a -n -p
使用 root 权限运行 netstat -anp
,输出
……
从整体上看,netstat
的输出结果可以分为两个部分:
一个是 Active Internet connections,称为有源 TCP 连接,即网络连接,我们用 netstat
命令看的主要也是这个部分,
-
Proto:协议,tcp6 指的是 IPV6 的 tcp 协议。
-
"Recv-Q" 和 "Send-Q" 指的是接收队列和发送队列。这些数字一般都应该是 0。如果不是则表示软件包正在队列中堆积。这种情况只能在非常少的情况见到。
-
Local Address:Linux 系统本机地址,
-
Foreign Address:系统外部地址,其中
0.0.0.0
和 127.0.0.1 指的都是本地,这是 IPV4 的格式,:::
指的也是本地,是 IPV6 的格式。
我们可以很明显地看到 22 端口的监听(SSH):
172.16.20.1
,指的其实就是 Linux 的宿主机:Windows,也就是我的 xshell 的所在的电脑,
所以这里实际上就是从宿主机的 55750 端口到虚拟机的 22 端口的一个 ssh 网络连接。
如果有多条,说明 xshell 里开了多个 ssh 连接。
一旦用户退出,ssh 连接断开,这一条网络连接信息就会消失,有时候也会有 TIME-WAIT
的中间过渡状态(这是由 TCP 协议的机制决定的)。
另一个是 Active UNIX domain sockets,称为有源 Unix 域套接口 (和网络套接字一样,但是只能用于本机通信,也就是本机内部的通信性能可以提高一倍)。
-
Proto 显示连接使用的协议,
-
RefCnt 表示连接到本套接口上的进程号,
-
Types 显示套接口的类型,
-
State 显示套接口当前的状态,
-
Path 表示连接到套接口的其它进程使用的路径名。
State 的类型
-
LISTEN:侦听来自远方的 TCP 端口的连接请求
-
SYN-SENT:再发送连接请求后等待匹配的连接请求(如果有大量这样的状态包,检查是否中招了)
-
SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认(如有大量此状态,估计被 flood 攻击了)
-
ESTABLISHED:代表一个打开的连接
-
FIN-WAIT-1:等待远程 TCP 连接中断请求,或先前的连接中断请求的确认
-
FIN-WAIT-2:从远程 TCP 等待连接中断请求
-
CLOSE-WAIT:等待从本地用户发来的连接中断请求
-
CLOSING:等待远程 TCP 对连接中断的确认
-
LAST-ACK:等待原来的发向远程 TCP 的连接中断请求的确认(不是什么好东西,此项出现,检查是否被攻击)
-
TIME-WAIT:等待足够的时间以确保远程 TCP 接收到连接中断请求的确认
-
CLOSED:没有任何连接状态
本地 IP 地址和远程 IP 地址都是 0.0.0.0
,这表示通信还没开始,IP 地址不确定,进程的状态也是 LISTEN
UDP 协议中套接字不绑定对方的地址和端口,因此这里显示 *:*
。
这部分《网络是怎样连接的》的《用电信号传输 TCP/IP 数据 —— 探索协议栈和网卡》的 套接字的实体就是通信控制信息
。
常用:
netstat -i
:显示网卡列表,跟 ifconfig
查看的结果一样
netstat -a
:列出所有端口 (包括监听和未监听的)
netstat -at
:列出所有 TCP 协议端口
netstat -au
:列出所有 UDP 协议端口
netstat -l
:只显示正在监听的端口
netstat -lt
:只显示正在监听的 TCP 端口
netstat -lu
:只显示正在监听的 UDP 端口
netstat -s
:显示所有端口的统计信息
netstat -st
:显示 TCP 端口的统计信息
netstat -su
:显示 UDP 端口的统计信息
netstat -ap
,列出所有端口,加上进程信息 -p
netstat -c
:将每隔一秒输出网络信息。
经常是对 netstat -anp
的结果再进行二次的搜索 ,比如
netstat -anp | grep ssh
netstat -anp | grep ':80'
……
常见问题处理
大量的 TCP 连接的状态为 CLOSE_WAIT
背景知识
参考《网络是怎样连接的》的《用电信号传输 TCP/IP 数据 —— 探索协议栈和网卡》的
数据收发操作小结
小节
原因
Linux 服务器 tcp socket 常见的几种状态:ESTABLISHED、TIME_WAIT、CLOSE_WAIT。
TCP 协议中描述,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。
提供网络服务时,需要特别关注两种状态:CLOSE_WAIT 和 TIME_WAIT。如果过多,可能导致 socket 资源耗尽,无法正常提供服务。
-
ESTABLISHED:表示正在 socket 通信。
-
TIME_WAIT(第 3 步以后):表示请求的客户端主动关闭 socket 而形成的状态。等待 2MSL 时间,约 4 分钟。主要是防止最后一个 ACK(第 4 步)丢失。由于 TIME_WAIT 的时间会非常长,因此服务端应尽量减少主动关闭连接。之所以设计 TIME_WAIT 状态,是为了考虑 ACK(第 4 步)丢失的情况发生,服务端将重发 FIN(第 3 步),客户端必须维护 TCP 状态信息以便可以重发最终的 ACK(第 4 步),否则会发送 RST,结果服务端认为发生错误。
-
CLOSE_WAIT(第 1 步以后):表示服务端被动关闭 socket。根据 TCP 状态机,服务器端收到客户端发送的 FIN,则按照 TCP 实现发送 ACK,因此进入 CLOSE_WAIT 状态。但如果服务器端不执行 close(),就不能由 CLOSE_WAIT 迁移到 LAST_ACK,则系统中会存在很多 CLOSE_WAIT 状态的连接。
也就是说,TIME_WAIT、CLOSE_WAIT 不可能出现在一台主机的一个 TCP 连接中,他要么是主动关闭的一方,要么是被动关闭的一方。
主动关闭的一方的状态变化过程是 主动关闭 -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED。
被动关闭的一方的状态变化过程是 被动关闭 -> CLOSE_WAIT -> LAST_ACK -> CLOSED。
Linux 服务器出现大量的 CLOSE_WAIT 后,socket 资源会被耗尽。因为 Linux 分配给一个用户的文件句柄是有限的,而 TIME_WAIT 和 CLOSE_WAIT 两种状态如果一直被保持,则文件句柄也就不能 close,导致句柄资源达到上线,接着就会出现大量 Too Many Open Files 错误。
如果出现大量 CLOSE_WAIT,首先需要考虑被动关闭方的程序是否有 BUG,是否有 socket 泄露(遗漏 close())。如果别的机器上能够正常访问,TCP 正常连接,那么就不是代码问题,那么就要关注网络问题,是不是因为主动关闭方的 ACK 号(第 3 步)因为网络问题无法发送到被关闭方。导致被关闭方一直 CLOSE_WAIT/LAST_ACK。
查看当前系统中的 tcp socket 状态信息并统计:
netstat -anp | grep TIME_WAIT | wc -l
netstat -anp | grep CLOSE_WAIT | wc -l
处理方法
CLOSE_WAIT:把占用的线程 kill
掉即可,如果是 TIME_WAIT,过一段时间,就会自己释放。