一、连接过程与状态
1、各状态解释:
CLOSED:没有任何连接状态
SYN-SENT:在发送连接请求后,等待对方确认
LISHEN:监听状态,等待客户端TCP端口的连接请求
SYN-RECEVED:接收到客户端发来的连接请求,已发送连接请求,等待对方确认
ESTABLISHED:代表传输连接建立,双方进入数据传送状态
----------------------------------------------------------------------------------------------------
FIN-WAIT1:主动关闭,客户端已发送关闭连接请求,等待服务器确认
FIN-WAIT2:主动关闭,客户端已收到服务器关闭传输连接确认,等待对方发送关闭传输连接请求
TIME-WAIT:完成双向连接传输关闭,等待所有分组消失
CLOSE-WAIT:被动关闭,收到对方发来的关闭连接请求,并已确认
LAST-ACK:被动关闭,等待最后一个关闭传输连接确认,并等待所有分组消失
CLOSING:双方同时尝试关闭传输连接,等待对方确认。
2、查看linux进程的TCP通信状态
使用命令:ss -ntap
参数解析:
-n, --numeric don't resolve service names
//这里的意思是不解析【:port】项的端口号为服务名
-t, --tcp display only TCP sockets
-a, --all display all sockets
//不加a默认只查看ESTAB状态
-p, --processes show process using socket
iptables与ssh命令结合,查看SYN-SENT状态
在A上使用iptables命令丢弃目的地址为B的数据包,A与B尝试建立SSH通信,在A上查看状态:
在A上:
iptables -A OUTPUT -d 192.168.80.99 -j DROP
ssh 192.168.80.99
查看状态:ss -nta
3、客户端先发送一个FIN给服务器,自己进入FIN-WAIT1状态,等待接收服务器端报文,这时会出现三种可能:
① 只有服务器端的ACK
只收到服务器的ACK,客户端会进入FIN-WAIT2状态,后续当收到服务器端的FIN时,回应发送一个ACK,进入TIME-WAIT状态,这个状态会持续保留2MSL(TCP报文在网络中的最大生存时间)。
② 只有服务器端的FIN
客户端回应ACK给服务器,进入CLOSING状态,接收到服务器ACK时,进入TIME-WAIT状态。
③ 既有ACK,又有FIN
同时收到服务器端的ACK和FIN,直接进入TIME-WAIT状态。
二、sysns queue 与 accept queue
1、syns queue
当服务器接收到客户端第一次SYN连接请求时,将创建的request_sock结构存储在syns半连接队列中,然后向客户端发送【SYN,ACK】报文。此时服务器处于SYN-RECEVE状态。
2、accept queue
当服务器收到客户端ACK时,将半连接队列相应条目删除,然后将相应的连接放入accept队列中,此时服务器端连接状态为ESTABLISTHENED。进入accept queue中的连接等待accept()调用。
3、linux内核中TCP的调优参数
查看帮助:man 7 tcp
示例:
① 查看和修改客户端的动态端口范围
cat /proc/sys/net/ipv4/ip_local_port_range
echo 32789 60999 > /proc/sys/net/ipv4/ip_local_port_range
② 查看和修改TCP的MSL
cat /proc/sys/net/ipv4/tcp_fin_timeout
sysctl net.ipv4.tcp_fin_timeout=80
③ 查看syns queue和syns queue队列长度
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
//syns queue大小,默认值128
cat /proc/sys/net/core/somaxconn
//accept queue大小,默认值128
三、python实现简易版TCP通信
客户端:
import socket
# 1 创建socket
sock = socket.socket()
# 2 连接
addr = ("127.0.0.1", 8088)
sock.connect(addr) #完成TCP三报文握手
# 3 数据处理
msg = "hello, im the client.".encode("utf-8")
sock.send(msg)
data = sock.recv(1024)
print("接收:", data.decode())
# 4 断开连接 释放资源
sock.close()
服务端:
import socket
# 1 创建socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# sock = socket.socket()
# 2 绑定
addr = ("0.0.0.0", 8088)
sock.bind(addr)
# 3 监听
sock.listen(1) #设置最长半连接数队列数长度为1
print("服务器正在监听...",addr)
while True:
# 4 接受连接
conn, addr_client = sock.accept() #全连接队列中取出连接
print("已连接", addr_client)
# 5 数据处理(接受数据,发送数据)
data = conn.recv(1024)
print("收到:", data.decode("utf-8"))
msg = "i am the server。".encode("utf-8")
conn.send(msg)
# 断开连接
conn.close()
# 6 释放资源
sock.close()
参考链接: