tcp
三握四挥

1 | (1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。 |
Time Wait
概念
- 谁先关闭谁最后进入timewait状态,time_wait 状态下,TCP 连接占用的端口,无法被再次使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17close 短连接
每个HTTP请求都需要重新完成TCP三次握手建立连接,数据传输完成后四次挥手关闭连接
keep-alive 长连接
在HTTP1.1协议中默认长连接,有个 Connection 头,Connection有两个值,close和keep-alive,这个头就相当于客户端告诉服务端,服务端你执行完成请求之后,是关闭连接还是保持连接,保持连接就意味着在保持连接期间,只能由客户端主动断开连接。还有一个keep-alive的头,设置的值就代表了服务端保持连接保持多久
#ngx
keepalive 100; # 保持的空闲连接数
keepalive_timeout 60s; # 空闲超时时间
keepalive_requests 100; # 单连接最大请求数
location / {
proxy_pass http://backend_servers;
proxy_http_version 1.1; # 关键:使用 HTTP/1.1
proxy_set_header Connection ""; # 清除 Connection 头(避免传递错误值)
}
# Linux 内核参数(默认值通常为 7200 秒)默认不启用
sysctl -w net.ipv4.tcp_keepalive_time=1800 # 空闲 1800 秒后发送探针
sysctl -w net.ipv4.tcp_keepalive_probes=3 # 发送 3 次无响应后关闭
sysctl -w net.ipv4.tcp_keepalive_intvl=15 # 每次探针间隔 15 秒
相关参数
1 | netstat -ant | awk '/^tcp/ {++y[$NF]} END {for(w in y) print w, y[w]}' |
CLOSE_WAIT
- 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。CLOSE_WAIT一般是由于对端主动关闭,而我方没有正确处理的原因引起的,临时解决重启服务,永久解决就是修改程序逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41客户端(主动关闭方) 服务器(被动关闭方)
| |
|--- GET /bigfile.zip --------->|
|<--- 200 OK + 文件数据 ---------|
| |
|--- FIN (我要关闭) ------------>| → 客户端进入 FIN_WAIT_1
|<--- ACK ----------------------| → 服务端进入 CLOSE_WAIT
| |(此时服务端还在发送剩余文件数据)
|<--- 剩余数据包 ----------------|
|<--- FIN (我也关闭) ------------| → 服务端进入 LAST_ACK
|--- ACK ----------------------->| → 客户端进入 TIME_WAIT
#没有调用s.close()关闭socket,会造成大量CLOSE_WAIT
import socket
import time
def create_sockets(num_sockets):
sockets = []
for _ in range(num_sockets):
# 创建一个 TCP 套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print(f"创建 socket {_ + 1}: {s.fileno()},状态为 alloc")
sockets.append(s)
return sockets
if __name__ == "__main__":
num_sockets = 10
while True:
num_sockets += 10
sockets = create_sockets(num_sockets)
print(f"总共创建了 {num_sockets} 个 socket 对象。")
time.sleep(10)
#shell
cat /proc/net/sockstat | grep sockets | awk '{print $3}'
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
for i in `ls /proc/ |grep '[0-9]'`
do
mycount=`ls /proc/$i/fd|wc -l`
echo "$i $mycount"
done
