TCP/IP握手和分手
2020-08-10 11:35:54 2 举报
AI智能生成
网络编程之TCPIP分手和握手的过程
作者其他创作
大纲/内容
Four Layers of TCP/IP Protocol
TCP
关键词
可靠
四次分手
主动关闭连接一端(active close),
才有TIME_WAIT状态
才有TIME_WAIT状态
半关闭状态/half-close
为啥挥手需要四次?
FIN报文,只表示发送端不再发送数据了,但还能接收数据
服务器收到客户端的FIN报文时,先回一个ACK应答报文,
而服务器端还可能有数据需要处理和发送,等服务端不再
发送数据是,才发送FIN报文给客户端,表示现在同意关闭连接。
而服务器端还可能有数据需要处理和发送,等服务端不再
发送数据是,才发送FIN报文给客户端,表示现在同意关闭连接。
因为客户端和服务器端的ACK和FIN需要分开发送,所以需要四次
为什么TIME_WAIT等待时间是2MSL?
MSL:Maxmum Segment Lifetime报文最大生存时间。
任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
IP头有一个TTL字段,表示IP数据包可以经过的最大路由数,每经过
一个路由器此值减一,当TTL=0时,此数据包被丢弃。
MSL是时间,TTL是经过路由跳数。所以理论上MSL应该大于等于TTL.
一个路由器此值减一,当TTL=0时,此数据包被丢弃。
MSL是时间,TTL是经过路由跳数。所以理论上MSL应该大于等于TTL.
极端情况下,网络中可能存在来自发送方的数据包,当这些发送方的
数据包被接收方处理后又被对方发送响应,所以一来一回要等待2倍的时间。
数据包被接收方处理后又被对方发送响应,所以一来一回要等待2倍的时间。
如果TIME_WAIT时间内,因为客户端的ACK还没有传输到服务端,
客户端又接收到了服务端重发的FIN报文,那么2MSL时间将重新计时。
客户端又接收到了服务端重发的FIN报文,那么2MSL时间将重新计时。
Linux系统TIME_WAIT的时间为固定的60秒
#define TCP_TIMEWAIT_LEN (60*HZ)
#define TCP_TIMEWAIT_LEN (60*HZ)
为什么需要TIME_WAIT状态?
防止旧连接的数据包
足以让两个方向的数据包都被丢弃,
使得原来连接的数据包在网络中都
自认消失,再出现的数据包一定都
是新建立连接产生的。
使得原来连接的数据包在网络中都
自认消失,再出现的数据包一定都
是新建立连接产生的。
保证连接正确关闭
等待足够的时间以确保最后的ACK能让被动关闭方接收,从而帮助其正常关闭
如果服务器端没有收到四次握手中的最后一个ACK报文,则会重发 FIN 关闭连接报文并等待新的 ACK 报文
客户端在TIME_WAIT状态等待2MSL后,就可以保证双方的连接都可以正常的关闭
TIME_WAIT过多的危害
内存资源占用
对端口资源的占用,一个TCP连接至少消耗一个本地端口
可以通过以下参数设定:net.ipv4.ip_local_port_range
可以通过以下参数设定:net.ipv4.ip_local_port_range
如果占满了所有端口,则会导致无法创建新连接。
TIME_WAIT优化
方法一:net.ipv4.tcp_tw_reuse 和 tcp_timestamps
可以复用处于TIME_WAIT 的 socket 为新的连接所用
如果引入时间戳,则2MSL问题就不复存在了。
因为重复的数据包会因为时间戳过期被自然丢弃。
因为重复的数据包会因为时间戳过期被自然丢弃。
方法二:net.ipv4.tcp_max_tw_buckets
默认值为18000
默认值为18000
当系统中处于TIME_WAIT的连接一旦超过这个值时,
系统就会将所有的TIME_WAIT 连接状态重置。
系统就会将所有的TIME_WAIT 连接状态重置。
不推荐
方法三:程序中使用 SO_LINGER
struct linger so_linger;
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));
如果l_onoff为非 0, 且l_linger值为 0,那么调用close后,会立该发送
一个RST标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了
TIME_WAIT状态,直接关闭。
so_linger.l_onoff = 1;
so_linger.l_linger = 0;
setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));
如果l_onoff为非 0, 且l_linger值为 0,那么调用close后,会立该发送
一个RST标志给对端,该 TCP 连接将跳过四次挥手,也就跳过了
TIME_WAIT状态,直接关闭。
不推荐
如果已经建立了连接,
但是客户端突然发生故障,怎么办?
但是客户端突然发生故障,怎么办?
原理:如果没有任何连接相关的活动,TCP keepalive每隔一个时间间隔,
发送给一个探测报文,如果联系几个探测报文都没有得到响应,则认为当
前的TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。
发送给一个探测报文,如果联系几个探测报文都没有得到响应,则认为当
前的TCP连接已经死亡,系统内核将错误信息通知给上层应用程序。
内核参数,默认值:
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9
tcp_keepalive + (tcp_keepalive_intvl * tcp_keepalive_probes)
Linux系统经过2小时11分15秒
Linux系统经过2小时11分15秒
需要考虑的情况
正常工作,TCP keepalive被重置
对端程序崩溃并重启,对端可以响应,但由于没有改连接的有效信息,
会产生RST报文,这样TCP连接被重置
会产生RST报文,这样TCP连接被重置
对端崩溃,或不可到达。达到keepalive的次数后,TCP会报告该TCP连接已经死亡
三次握手
为啥需要三次握手?
目的:初始化Socket, 序列号和窗口大小并建立连接
三次握手才可以
阻止重复历史连接的初始化
造成混乱。
阻止重复历史连接的初始化
造成混乱。
历史连接情况图例
如果是两次握手,不能判断当前连接是否是历史连接。
三次握手的时候,客户端在准备发出第三次报文时,有足够的上下文信息来判断当前连接是否是历史连接:
1. 如果是历史连接,则发送RST报文,中止历史连接;
2. 如果不是历史连接,则发生ACK报文,通信双方成功建立连接。
三次握手的时候,客户端在准备发出第三次报文时,有足够的上下文信息来判断当前连接是否是历史连接:
1. 如果是历史连接,则发送RST报文,中止历史连接;
2. 如果不是历史连接,则发生ACK报文,通信双方成功建立连接。
三次握手才可以同步双方的初始序列号
序列号是可靠传输的关键因素。
握手时,一来一回,才能确保双方的初始序列号能被可靠的同步。
握手时,一来一回,才能确保双方的初始序列号能被可靠的同步。
三次握手才可以避免资源浪费
如果只是两次握手,当客户端发送SYN请求在网络中阻塞,
客户端没有收到ACK,就会重发SYN,由于没有第三次握
手,服务器不清楚客户端是否收到了自己发送的建立连接
的ACK确认报文,所以每个SYN就只能主动建立一个连接,
建立多个冗余的无效链接,造成资源浪费。
客户端没有收到ACK,就会重发SYN,由于没有第三次握
手,服务器不清楚客户端是否收到了自己发送的建立连接
的ACK确认报文,所以每个SYN就只能主动建立一个连接,
建立多个冗余的无效链接,造成资源浪费。
可靠
TCP头
重要控制位
SYC
"1"表示希望建立连接,
并初始化"序列号"(ISN)的字段
并初始化"序列号"(ISN)的字段
第一个发出SYN:active open
第二个回复SYN:passive open
ACK
"1"表示“确认应答”字段有效
RST
1时,表示TCP连接中出现异常,必须强制断开连接
FIN
1时表示今后不再有数据发送,希望断开连接
包称之为 Segment
TCP的负载数据的长度
TCP数据长度 = IP总长度 - IP首部长度 - TCP首部长度
定义:TCP是面向连接的、可靠的、
基于字节流的传输层通信协议
TCP provides a reliable flow of
data between two hosts
基于字节流的传输层通信协议
TCP provides a reliable flow of
data between two hosts
面向连接/Connection-oriented
必须一对一
可靠
无损坏
无间隔
非冗余
按序
字节流
消息没有边界,无论多大都可以进行传输
消息是有序的
即使先收到后面的字节,
也不会交给应用层处理,
同时对“重复”的报文
会自动丢弃
也不会交给应用层处理,
同时对“重复”的报文
会自动丢弃
可靠性和流量控制的信息
sockets
IP + Port
序列号
sequence numbers
sequence numbers
解决乱序问题
可靠连接的关键因素
去除重复的数据
按序接收
可以标识发送出去的数据包中,
哪些是已经被对方收到的
哪些是已经被对方收到的
窗口大小
window size
window size
用来做流量控制
By default 4096, 存在于每个包中
TCP四元组
源地址
32bit, 在IP头
源端口
目的地址
32bit, 在IP头
目的端口
最大TCP连接数
连接数 = 客户端IP数 x 客户端的端口数
限制条件
文件描述符限制
Unix中所有都是文件:socket也是文件
内存限制
客户端和服务端初始序列号是不相同的。
网络中的报文传输会延迟,会复制重发,也可能丢失。所以各自维护不同的随机初始序列号。
初始序列号产生算法
ISN = M + F(localhost, localport, remotehost, remoteport)
M: 计时器,每4ms递增
F : hash算法,生成一个随机数值。
M: 计时器,每4ms递增
F : hash算法,生成一个随机数值。
既然IP层会分片,为什么TCP层还需要MSS呢?
基础知识
IP层分片原理:
当IP层发现整个报文超过MTU,则IP层自动进行分片,而保证么一个分片小于MTU。
分片后,有目标主机的IP层来进行重新组装,再交给上一层TCP传输层。
问题:
当如歌一个IP分片丢失,整个IP报文的所有分片都必须重传。因为IP层本身没有超时
重传机制,它有传输层的TCP来负责超时和重传。
当接收方发现TCP报文的某一片丢失后,则不会响应ACK给对方,那么发送方的TCP
在超时后,就会重发整个TCP报文(头部+数据)。
当IP层发现整个报文超过MTU,则IP层自动进行分片,而保证么一个分片小于MTU。
分片后,有目标主机的IP层来进行重新组装,再交给上一层TCP传输层。
问题:
当如歌一个IP分片丢失,整个IP报文的所有分片都必须重传。因为IP层本身没有超时
重传机制,它有传输层的TCP来负责超时和重传。
当接收方发现TCP报文的某一片丢失后,则不会响应ACK给对方,那么发送方的TCP
在超时后,就会重发整个TCP报文(头部+数据)。
解决方案:建立连接时,协商双方的MSS值,当TCP发现数据超过MSS(以太网时为1460Bytes)
时,则先会进行分片。如果TCP分片丢失,进行重发也是以MSS为单位。
时,则先会进行分片。如果TCP分片丢失,进行重发也是以MSS为单位。
SYN攻击
攻击者短时间伪造不同IP地址的SYN报文,服务端每接收到一个SYN报文,
就进入SYN_REVD状态,但服务端发送出去的ACK+SYN报文,无法得到
未知IP主机的ACK应答,久而久之就会占满服务端的SYN接收队列(未连接队列)
就进入SYN_REVD状态,但服务端发送出去的ACK+SYN报文,无法得到
未知IP主机的ACK应答,久而久之就会占满服务端的SYN接收队列(未连接队列)
正常流程
避免方法一
修改Linux内核参数,控制队列大小和当队列满是应做什么处理。
当网卡接收数据包的速度大于内核处理的速度是,会有一个队列保存这些数据包。控制对垒的最大值的参数:
net.core.netdev_max_backlog
net.core.netdev_max_backlog
SYN_RCVD状态连接的最大个数:
net.ipv4.tcp_max_sync_backlog
net.ipv4.tcp_max_sync_backlog
超出处理能力是,对新的SYN直接回报RST,丢弃连接:
net.ipv4.tcp_abort_on_overflow
net.ipv4.tcp_abort_on_overflow
避免方法二
tcp_syncookies方式应对SYN攻击:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_syncookies = 1
1. 当"SYNC队列"满之后,后续服务器收到的SYNC包,不进入"SYNC队列"
2. 计算出一个cookie值,再以SYN+ACK中的“序列号”返回客户端
3. 服务端接收到客户端的应答报文时,服务器会检查这个ACK包的合法性。如果合法,直接放到"Accept队列"
4. 最后应用通过accept() socket接口,从"Accept队列"取出连接
2. 计算出一个cookie值,再以SYN+ACK中的“序列号”返回客户端
3. 服务端接收到客户端的应答报文时,服务器会检查这个ACK包的合法性。如果合法,直接放到"Accept队列"
4. 最后应用通过accept() socket接口,从"Accept队列"取出连接
IP
不可靠
不保证网络包的交付
不保证网络包的按序交付
不保证网络包中数据的完整性
UDP头
不需要连接/Connectionless
TCP VS UDP
连接
服务对象
可靠性
拥塞控制、流量控制
子主题
性质区别
连接
服务对象
TCP 1 to 1
UDP 1 to 1/ 1 to Multi / Multi to Multi
可靠性
拥塞控制、流量控制
即使网络非常拥堵了,仍不会
影响UDP的发送速率
影响UDP的发送速率
头部开销
TCP>= 20 Bytes 在不考虑"选项”字段的时候
UDP = 8 Bytes
应用场景
TCP面向可靠传输
FTP/HTTP/HTTPS
UDP
包总量较少的通信
DNS/SNMP
视频、音频等多媒体通信
广播通信
三次握手
第一个报文
SYN
- 客户端 OUT 流打开,等待服务端确认
不可带数据
第二个报文
SYN + ACK
- 服务端确认输入流正常,
- 打开输出流,等待客户端确认
不可带数据
第三个报文
ACK
- 客户端确认输入流正常。
可以带数据
TCP Socket编程
模型
握手和连接
关闭图解
要点
服务器端调用accept()时,返回一个已经完成三次握手,建立连接的socket,所有后续通信通过此socket
监听socket != 传输数据的socket
0 条评论
下一页