别的不说,先上代码(^-^代码:谁要上我?)
# socket_server.py
import socket,sys
ser=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ser.bind(('192.168.199.1',int(sys.argv[1])))
ser.listen(5)
while 1:
client,addr=ser.accept()
client.close() #这里当客户的连接服务器之后 服务器立即断开
# socket_client.py
import socket,time,sys
def client():
mysocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
mysocket.connect(('192.168.199.1',int(sys.argv[1])))
return mysocket
socket_list=[]
try:
while True:
socket_list.append(client()) # 客户端保持连接并创建新的连接
except Exception as err:
print(err)
print("Conn count:%d" % len(socket_list))
time.sleep(1000)
这两段程序就是模拟产生大量close_wait
# 在IP为192.168.199.1的服务器上执行
[root@server ~]# python socket_server.py 8001
# 在IP为192.168.199.74的终端上执行
[root@client ~]# python socket_client.py 8001 &
[1] 2046
[root@client ~]# [Errno 99] Cannot assign requested address
Conn count:28232
[root@client ~]# telnet 192.168.199.1 8001
Trying 192.168.199.1...
telnet: connect to address 192.168.199.1: Cannot assign requested address
我们可以发现,在程序结束之前,我们是连不上这个端口了。
注: 这里之前是最大1024个,报错信息:socket.error: [Errno 24] Too many open files,原因是因为每个程序默认只能打开1024个文件描述符. 执行ulimit -n 65535临时增加程序允许打开的文件描述符数量。
那么问题来了:
为什么是28232个连接?
通过查阅资料,原因是因为内核参数的限制,可通过修改此参数来增大最大连接数
因为客户端每次连接服务器,本地都会打开一个端口,而这个端口会从这个内核参数限制的范围来取,取完了就不能再连接了[root@client ~]# sysctl -a |grep port_range net.ipv4.ip_local_port_range = 32768 60999
然后再继续探究
# 在IP为192.168.199.1的服务器上执行
[root@server ~]# python socket_server.py 8001
[root@server ~]# python socket_server.py 8002
[root@server ~]# python socket_server.py 8003
# 在IP为192.168.199.74的终端上执行
[root@client ~]# free -h
total used free shared buffers cached
Mem: 1.9G 242M 1.6G 508K 9.1M 63M
-/+ buffers/cache: 170M 1.7G
Swap: 2.0G 0B 2.0G
[root@client ~]# python socket_client.py 8001 &
[1] 2076
[Errno 99] Cannot assign requested address
Conn count:28232
[root@client ~]# python socket_client.py 8002 &
[2] 2077
[Errno 99] Cannot assign requested address
Conn count:28232
[root@client ~]# python socket_client.py 8003 &
[3] 2078
[Errno 99] Cannot assign requested address
Conn count:28232
[root@client ~]# free -h
total used free shared buffers cached
Mem: 1.9G 695M 1.2G 548K 10M 65M
-/+ buffers/cache: 619M 1.3G
Swap: 2.0G 0B 2.0G
[root@client ~]# netstat -an|wc -l
84787
[root@client ~]# netstat -an|grep 33768
tcp 1 0 192.168.199.74:33768 192.168.199.1:8001 CLOSE_WAIT
tcp 1 0 192.168.199.74:33768 192.168.199.1:8002 CLOSE_WAIT
tcp 1 0 192.168.199.74:33768 192.168.199.1:8003 CLOSE_WAIT
[root@client ~]# iostat -x 1
avg-cpu: %user %nice %system %iowait %steal %idle
0.00 0.00 0.00 0.00 0.00 100.00
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await r_await w_await svctm %util
vda 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
dm-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
通过htop查看三个python进程每个使用23M的内存,算下来系统因创建连接开销为450M,估算出每个连接会占用5KB的内存。检查cpu和磁盘io都没有受到影响
但是问题又来了
- 为什么同时开了3个相同的端口,明明端口未释放但是又能通过这个端口创建了一个新的连接
(问题待解决)
综上所述close_wait对系统影响:
1. 占用系统内存
2. 如果连接数满了就不能对相应的对段端口创建连接了
3. 假设你的程序会去连接另一个服务,而未正常关闭,那么可能导致你的程序超过最大连接数的时候报异常,引起连锁反应甚至导致程序崩溃
4. 网上有说法可能会导致系统扫描端口连接,影响cpu,但是测试中未发现这个问题