一、TCP实现原理
1、协议介绍
TCP(传输控制协议,协议ID-6)提供面向连接且可靠的字节流服务,通过最大分段大小(MSS),应用数据被分割成合适的数据段,在以太网上MSS最大值为1500-20-20=1460字节,三次握手时由两端协商(SYN选项中),如果不设置,在因特网上默认MSS为536字节(一般取512的倍数,512字节),MTU = MSS + TCP Header + IP Header + Data
链路层长度为18字节,包含数据帧头(smac + dmac + proto = 14Byte)和帧尾(FCS = 4Byte),最大传输单元(MTU)长度一般为1500字节,网络层IP包首部长度最小为20字节,传输层UDP首部长度为8字节,所以应用层最大长度为1500-20-8=1472字节,大于则需要IP分片。在因特网上的标准MTU一般为576字节(以太网为1500),所以应用层数据长度最好限制在576-20-8=548字节,如果IP分片则IP数据包的最大长度为64K(IP首部描述长度的字段为2字节,最大表示65535字节)
2、TCP三次握手
客户端:CLOSED -> 发送SYN -> SYN_SEND -> 收到SYN+ACK并发送ACK -> ESTABLISHD 服务器::CLOSED -> 收到SYN -> LISTEN -> 发送SYN+ACK -> SYN_RECV -> 收到ACK -> ESTABLISHD 同时打开:CLOSED -> 发送SYN -> SYN_SEND -> 收到SYN并发送ACK -> SYN_RECV -> 收到ACK -> ESTABLISHD 为什么是三次:TCP为全双工,建立连接需要确认双方的收发通道正常,少于三次则服务器无法确认客户端的接受报文通道正常,大于三次则冗余
3、TCP四次挥手
客户端:ESTABLISHD -> 发送FIN -> FIN_WAIT1 -> 收到ACK -> FIN_WINT2 -> 收到FIN并发送ACK -> TIME_WAIT -> 等待2MSL -> CLOSED 服务器:ESTABLISHD -> 收到FIN并发送ACK -> CLOSE_WAIT -> 发送FIN -> LAST_ACK -> 收到ACK -> CLOSED 同时关闭:ESTABLISHD -> 发送FIN -> FIN_WAIT1 -> 收到FIN并发送ACK -> CLOSED 为什么是四次:被动关闭方可能还有数据未发送,所以主动关闭方发送FIN报文后,对端回复带负载的ACK,之后再发送FIN报文,如果没有数据发送则对端响应FIN+ACK报文,最后主动关闭端发送ACK是通知对端已收到FIN报文 TIME_WAIT状态:等待2MSL(最长报文段生存时间,RFC793规定120s,Centos默认60s),原因一是确保对端收到最后的ACK,防止ACK报文丢失对端重传FIN报文,或者一直是LAST_ACK状态RST SYN报文;原因二是防止接收到旧连接的延迟数据包 TIMW_WAIT过多:影响为占用过多的本地端口(服务器主动关闭),占用连接资源,新建TCP连接出错 TIMW_WAIT解决方案:一是调整系统内核参数(允许TIME_WAIT状态socket用于新的连接或者快速回收),修改HTTP短连接为长链接(keep-alive)
4、TCP拥塞控制
慢启动:连接建立后拥塞窗口(cwnd)初始化大小为MSS,每当收到一个ACK则拥塞窗口增加一个MSS,发送窗口实现指数增长1->2->4->8…
- 出现响应超时后,慢启动阈值(ssthresh)设置拥塞窗口值的一半,拥塞窗口重置为MSS,继续指数增长
- 拥塞窗口指数增长到慢启动阈值后,结束慢启动并开始拥塞避免模式,窗口进入线性增长
- 收到连续三次重复ACK,进入快重传和快恢复模式
拥塞避免:
- 乘法减小:无论是慢启动还是拥塞避免阶段,只要发生丢包,慢启动阈值均设置为拥塞窗口的一半
- 加法增大:拥塞窗口增长到慢启动阈值后,每经过一个往返时间(RTT)拥塞窗口增加MSS,线性增加防止窗口指数增长过快提前导致拥塞
快恢复:
- 收到连续三次重复ACK,执行拥塞避免乘法减小后,推断网络可能没有阻塞,所以不执行慢启动算法,将拥塞窗口设置为新的慢启动阈值+3MSS(三次重传ACK),然后执行拥塞避免加法增大
- 收到之前已发送所有报文的ACK后退出快恢复,重新设置拥塞窗口为慢启动阈值,再次执行加法增大
快重传:
- 接收方每收到一个失序报文段就立即发送重复确认ACK(为上一次发送的ACK)
- 发送方收到连续三次重复ACK则立刻重传接收方尚未确认的报文段
5、路由器拥塞控制
网络发生拥塞时路由器根据平均包长来随机丢弃TCP报文,使一部分连接放缓来保证其他连接正常 ECN(显式拥塞通知):通过TCP发送端和接收端以及路由器的配合感知路径拥塞,在路由器转发报文时,对超过平均长度的TCP报文进行ECN标记(IP首部TOS第7-8bit,00不支持,11发送拥塞),不再丢弃报文,报文到达接收端后,接收端响应ACK报文中对TCP ECE字段置位,以此来通知发送端将拥塞窗口缩小,发送端发送报文时将CWR字段置位
5、滑动窗口
根据时间轴分类:已发送已确认、已发送未确认、未发送已允许、未发送未允许 滑动窗口的作用:
- 流量控制,接收方通告自己的接受窗口大小,从而控制发送方的发送速率,以免出现丢包
- 可靠性,只有收到接收方在发送窗口内的ACK才会右移滑动窗口,保证已发送数据得到确认
6、TCP首部字段
源目的端口(sport/dport):2Byte,标识传输层与应用层的服务接口 序列号(seq):4Byte,标识当前报文的第一个字节序号,SYN和FIN均占用一个序列号 确认号(ack):4Byte,标识接收端期望收到的下一个报文第一个字节的序列号 首部长度(header):4Bit,整个首部长度,包含选项,单位为4Byte 保留位(reverse):4Bit,暂时保留为0 CWR:1Bit,标识减小拥塞窗口,发送方收到ack报文中ECE标记置位后设置,发送速率减半 ECE:1Bit,标识通知发送端减小拥塞窗口,接收方收到IP首部ECN字段置位11后设置(三次握手时ECE置位表示支持ECN功能) URG:1Bit,标识紧急指针字段有效,通知系统高优先级发送该报文段 ACK:1Bit,标识确认号字段有效 PSH:1Bit,标识收到PSH置位的报文应尽可能的不再等待缓存满再交付应用程序处理 RST:1Bit,标识收到报文后应释放连接 SYN:1Bit,标识连接请求 FIN:1Bit,标识数据已发送或接收完毕,请求释放连接 窗口大小:2Byte,标识数据接收窗口大小,扩容需要结合选项中窗口缩放因子 检验和:2Byte,包含首部和数据的检验,计算时需要在首部前增加12Byte伪首部(源IP 4Byte + 目的IP 4Byte + 保留 1Byte + 传输层协议号 1Byte + 首部加数据长度 2Byte),加入伪首部目的为防止接收到存在路由器的错误数据报 紧急指针:2Byte,标识当前报文段负载中紧急数据字节数,紧急数据在其他数据前 首部选项:最大长度40Byte,字段结构(KindType 1Byte + Length 1Byte + Value nByte),Length表示整个字段长度,包含Kind和Length 填充(NOP):1Byte,没有Length和Value字段,用来填充为4Byte的整数倍,每个选项不满足时前面均填充n个NOP 最大分段大小(MSS):4Byte,标识通知本端支持的最大分段大小,默认为536Byte 窗口缩放因子(WSPOT):3Byte,1Byte可用,标识通知本端窗口大小的左移位数,取值范围0-16(所以窗口最大32Byte),只能出现在SYN报文中,需要双方支持 时间戳(TSPOT):10Byte,包含时间戳字段和时间戳回显字段,发送方填充时间戳字段(本端内核时间),接收方回复时填充时间戳字段(本端内核时间)和时间戳回显字段(拷贝发送端的时间戳字段值),原因一是计算往返时延RTT,二是防止序列号回绕,即收到流量大时反转后的序列号(序列号为32位) 选择确认(SACK):(4 * 2 * N + 2)Byte,需要对端支持,即连接时对端发送SACK-Premitted选项;标识接收方已经接收的序列号范围,由N对序列号组成,由于选项长度限制,最大SACK块数N最大为4;第一块左序列号为已收到第一个乱序报文的序列号,右序列号为第一个乱序报文开始不连续的结束序列号+1,例如已收到乱序报文11-20和31-40,所以第一块左11,右21,第二块左31,右41,结合ACK就可以判断重传哪些报文
7、TCP分段重组
分段:需要传输的数据大于MSS时,对数据进行分段传输,每个报文段都包含TCP首部 重组:报文段到达接收方后,将应用层数据根据TCP首部序列号进行分段重组 TCP粘包:缓存多个应用需要发送的数据由单个报文段发出,TCP协议本身造成;一是发送方粘包,原因为应用连续几次发送的数据很小,TCP协议通过Nagle算法缓存N次数据包合并为一个报文段发出;二是接收方粘包,原因为应用接收数据不及时导致系统缓冲区堆积,一次取得多个数据包;粘包处理方法为->数据包发送前添加首部长度、发送固定长度数据、设置边界
8、网络编程模型
二、UDP实现原理
1、协议介绍
UDP(用户数据报协议,协议ID-17)提供面向报文的传输服务,是一种无连接低可靠性的协议,支持一对多或多对一传输数据 特点:
- 无连接,不需要建立连接,支持一对多或多对一传输数据
- 面向报文,一次交付一个完整报文
- 尽可能努力交付,协议本身没有可靠性机制,比如拥塞控制机制
- 首部开销小,节省资源
2、UDP首部 源目的端口(sport/dport):2Byte,标识传输层与应用层的服务接口 长度(Length):2Byte,标识udp首部和用户数据长度,最小8Byte 校验和:2Byte,包含首部和数据的检验,计算时需要在首部前增加12Byte伪首部(源IP 4Byte + 目的IP 4Byte + 保留 1Byte + 传输层协议号 1Byte + 首部加数据长度 2Byte),加入伪首部目的为防止接收到存在路由器的错误数据报
3、网络编程模型
三、IP实现原理
1、协议介绍
IP协议(网络互联协议)为传输层的承载协议,提供无连接且不可靠的数据包传输服务
2、IP首部
版本号(Version):4Bit,标识IP协议版本,0100-IPv4,0110-IPv6 首部长度(HdrLen):4Bit,标识首部长度,单位4Byte 服务类型(TOS):8Bit,1-3Bit为优先级(已弃用),4-7Bit标识服务类型,8Bit保留,RFC3168中7-8Bit被用来定义显式拥塞通知(ECN) 总长度(TotalLen):2Byte,标识首部和数据的长度,单位Byte 标识(Identifer):2Byte,和标志与片偏移联合使用,所有分片的标识值一样,用于分片重组 标志(Flags):3Bit,第1Bit保留,第2Bit为DF(Don’t Fragment)表示数据不能分片,第3Bit为MF(More Fregment)表示后面还有其他分片需要重组 片偏移(Fragments Offset):13Bit,标识数据包在所有分片中的位置,单位为8Byte 生存时间(TTL):1Byte,标识数据包的生存时间,每一次路由转发减1,为0丢弃,预防环路 协议(Protocol):1Byte,标识上层使用协议,1-ICMP 2-IGMP 6-TCP 17-UDP 首部校验和:2Byte,校验IP头部,路由器改变TTL需要重新计算 源目的IP:4Byte,除非使用NAT,否则地址不变
选项(Option):
- 松散源路由:填充途径路由器IP地址,使数据包沿这些地址传输数据包,允许两个IP之间经过多个路由器
- 严格源路由:同松散源路由,但不允许两个IP之间经过其他路由器
- 路由记录:记录每个路由转发出口IP地址
- 时间戳:记录每个路由转发时间
- 填充:IP首部单位为4Byte,所以可能需要填充
四、TCP和UDP的区别
|