环境信息
OS
: macOS
14.1.1 (23B81)Docker
: 24.0.5Image
: mysql
(8.0.21)
Linux 服务器下查看网络连接的状态
Linux
服务器下查看网络连接的状态, 通过 netstat
命令查看了当前tcp
链接的情况(本地测试,线上实际值大的多)
1 | # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' |
常用的三个状态是:ESTABLISHED
表示正在通信,TIME_WAIT
表示主动关闭,CLOSE_WAIT
表示被动关闭。
- CLOSED: 初始状态,
socket
连接未被使用 - LISTENING: 正在监听进入的连接
- SYN_SENT: 正在试着建立连接
- SYN_RECEIVED: 进行连接初始同步
- ESTABLISHED: 连接已被建立
- CLOSE_WAIT: 远程服务器关闭连接,正在等待
socket
连接的关闭 - FIN_WAIT_1:
socket
连接关闭,正在关闭连接 - CLOSING: 先关闭本地
socket
连接,然后关闭远程socket
连接,最后等待确认信息(特殊的状态,也比较少见,正常情况下不会出现) - LAST_ACK: 远程服务器关闭后,等待确认信号
- FIN_WAIT_2:
socket
连接关闭后,等待来自远程计算器的关闭信号 - TIME_WAIT: 连接关闭后,等待远程服务器关闭重发
可以使用 netstat -an
命令查看链接状态,进行了检查。
例如,查看所有 CLOSE_WAIT
的链:
1 | # netstat -an | grep TIME_WAIT |
抓自己的服务器的包
Linux
系统有很多块网卡,可以用 ifconfig -a
(显示或设置网络设备) 打出来,自己写的服务器一定要监听 lo
(本地环路接口)这块网卡,不然监听上网的那块网卡是监听不到的。
eth0
,eth1
,eth2
…代表网卡一,网卡二,网卡三…lo
代表127.0.0.1
,即localhost
查找本地 lo
网卡:
1 | # ifconfig -a | grep lo |
另外也可以使用nmcli dev status
命令查看网卡状态:
1 | # nmcli dev status |
TCP 抓包分析下
tcpdump
是对网络上的数据包进行截获的包分析工具,它支持针对网络层、协议、主机、网络或端口的过滤,并提供 and
、or
、not
等逻辑语句来去掉无用的信息。
例如,监听本地Docker
运行的MySQL
服务(端口 13306
)的数据包:
1 | sudo tcpdump -i lo0 host 127.0.0.1 and port 13306 |
参数说明:
X: 包的内容也可以查看的到
i: 指定要监听的网卡
-n: 指定将每个监听到数据包中的域名转换成IP
地址后显示,不把网络地址转换成名字
-nn: 指定将每个监听到的数据包中的域名转换成IP
、端口从应用名称转换成端口号后显示
-v: 输出一个稍微详细的信息,例如在IP
包中可以包括TTL
和服务类型的信息
-S: 打印绝对时间戳
-w mysql.pcap: 将抓到的包写入文件,生成的 pcap 文件可以用 tcpdump 或者 wireshark 之类的网络流量分析工具打开
host: 是IP
地址
port: 是端口号
抓包结果:
1 | 21:29:40.148304 IP localhost.59994 > localhost.13306: Flags [S], seq 1224152147, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 2485129604 ecr 0,sackOK,eol], length 0 |
FLAG[S]
意思是包中的标志是SYN
,这是一个请求包。FLAG[.]
一般是指明这是一个单一的 ack
确认包。
NOTE:Flags are some combination of S (SYN), F (FIN), P (PUSH), R (RST), W (ECN CWR) or E (ECN-Echo), or a single ‘.’ (no flags)
options 表示选项
mss 表示是发送端通告的最大报文长度
sackOK 表示发送端支持 SACK 选项,SACK 选项是为了更好的确定数据的准确接收的
TS val 发送端的时间戳 ecr 接收端的时间戳
wscale 表示窗口因子大小
如果 tcpdump
无法抓到数据包,可以考虑以下几种原因:
- 没有安装
libpcap
库:tcpdump
需要使用libpcap
库来抓取数据包,如果没有安装,请先安装。 - 没有足够的权限:
tcpdump
需要使用root
权限才能抓取数据包,使用sudo
命令运行tcpdump
。 - 网络配置问题: 如果网络配置不正确,
tcpdump
可能无法抓取数据包。请检查网络配置是否正确。 - 无数据: 如果当前网络中没有数据流动,
tcpdump
也无法抓取数据包。
如果以上原因都已经排除,请尝试使用其他工具来检测网络是否正常。
抓包分析
TCP 三次握手
- step 1:客户端执行系统调用
1
21:29:40.148304 IP localhost.59994 > localhost.13306: Flags [S], seq 1224152147, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 2485129604 ecr 0,sackOK,eol], length 0
connect()
发出SYN
请求建立TCP
连接,此时客户端的TCP
端口状态为SYN_SENT
(表示请求连接)。 - step 2:服务端执行系统调用
1
21:29:40.148352 IP localhost.13306 > localhost.59994: Flags [S.], seq 2879060989, ack 1224152148, win 65535, options [mss 16344,nop,wscale 6,nop,nop,TS val 1613321693 ecr 2485129604,sackOK,eol], length 0
listen()
监听到SYN
请求,TCP
端口状态从LISTEN
转为SYN_RCVD
并第一次响应ACK
。 - step 3:客户端接收到
1
21:29:40.148358 IP localhost.59994 > localhost.13306: Flags [.], ack 1, win 6379, options [nop,nop,TS val 2485129604 ecr 1613321693], length 0
ACK
响应之后,TCP
端口状态变成ESTABLISHED
(已建立连接,表示通信双方正在通信),再给服务端发送ACK
。服务端接收到ACK
之后,服务端的TCP
端口状态为ESTABLISHED
。
为什么要握手要三次?
防止失效的连接请求突然传到服务器端,让服务器端误认为要建立连接。
数据传输
双方建立通信之后,Clien
向 Server
正式发出请求:
1 | 22:56:02.009399 IP localhost.13306 > localhost.58189: Flags [P.], seq 1:79, ack 1, win 6379, options [nop,nop,TS val 1886650872 ecr 1513261871], length 78 |
Client
=> Server
:seq
= x+1, ack
= y+1 继承了第三次连接的 seq
和 ack number
请求长度 length
: 78,seq
1:79 == seq
1:[1+length
]
四次挥手
TCP
协议规定,对于已经建立的连接,收发双方要进行四次挥手才能成功断开连接,如果缺少了其中某个步骤,都会使连接处于假死状态,连接本身所占用的资源不会被释放。
step 1:
1
21:32:25.591866 IP localhost.59994 > localhost.13306: Flags [F.], seq 27, ack 1, win 6334, options [nop,nop,TS val 2485295047 ecr 1613321738], length 0
由
Client
提出断开连接请求FIN
(Flags [F.]
),Client
的TCP
端口进入FIN_WAIT_1
状态。step 2,3:
1
221:32:25.591885 IP localhost.13306 > localhost.59994: Flags [.], ack 28, win 6368, options [nop,nop,TS val 1613487136 ecr 2485295047], length 0
21:32:25.592202 IP localhost.13306 > localhost.59994: Flags [F.], seq 1, ack 28, win 6368, options [nop,nop,TS val 1613487136 ecr 2485295047], length 0Server
发送ACK
应答,Server
的TCP
端口进入CLOSE_WAIT
状态,Client
的TCP
端口进入FIN_WAIT_2
状态。几乎同时Server
还发送了一个FIN
端口连接请求,进入LAST_ACK
状态。step 4:
1
21:32:25.592247 IP localhost.59994 > localhost.13306: Flags [.], ack 2, win 6334, options [nop,nop,TS val 2485295047 ecr 1613487136], length 0
Client
进行ACK
应答(LAST ACK
),进入TIME_WAIT
(两倍的分段最大生存期),并最终变成CLOSED
状态。
为什么进入
TIME_WAIT
状态后必须等待2MSL
后才能返回CLOSED
状态?
- 保证发送的最后一个
ACK
报文段能达到- 防止失效的报文段出现在连接中
参考
- https://blog.csdn.net/a772304419/article/details/126426636
- https://www.jianshu.com/p/f6b254e98b39
- https://focus-1.wiki/computer-network/tcpdump-tcp-3-and-4/
以上。