Tcp学习笔记
Published:
TCP, UDP协议学习笔记
UDP校验和
计算方法
- 将报文段中所有的16比特的和进行反码运算,如果溢出则进行回卷。
- 回卷操作:将溢出的位加到最低位
- 将报文段中所有的16比特的和进行反码运算,如果溢出则进行回卷。
报文段中的16比特字:源端口号,目的端口号,长度,原校验和
例子
0110011001100000 0101010101010101 1000111100001100 -> overflow + => 010010101000001 回卷:010010101000010 ~ :101101010111101 RECEIVER: 在加上原校验和取反, 若不为1111111111111111, 则说明分组中有差错,未正确传输
处理:弃用该报文段
TCP
Maximum Segment size(MSS): TCP可从缓存中取出并放入报文段的最大限度
- 由MTU(maximum transmission unit) 确定, 最大链路层帧长度
报文结构
32 bit - source port: destination port (16 each) - sequence number (32) - acknowledgement number(32) - head length;reserved; CWR/ECE/URG/ACK/PSH/RST/SYN/FIN; RECEIVER WINDOW - checksum field/ emergency data pointer - options (协商MSS,以及时间戳选项) - data
- 传输较大文件:划分成若干个长度为MSS的小块
PSH
选项:接受方立即将数据返回上层RST
,SYN
,FIN
选项:用于连接的建立和拆除UGR
指示紧急数据CWR
拥塞窗口flag,明确拥塞报告
三次握手详细:
第一次:a->b 没有数据,但首部的SYN flag被标记, 随机选取初始序号(client_isn)
第二次:b->a b将为此连接分配内存,发送包:SYN = 1, ACK = client_isn++, SEQ = 随机选取sever_isn (SYNACK报文段)
第三次:a->b a将为此连接分配内吨,发送包:SYN = 0, ACK = server_isn++, SEQ = client_isn++;
此次发送的包可以有负载
结束连接:
- 与握手类似,只是FINflag将被标记,服务器收到FIN将再发一个带ACK的FIN包然后关闭,最后客户将再发一个包并定时等待,确认服务器关闭(没有包过来)后则关闭
序列号和确认号
例子,若MSS为1000字节,则序号为0, 1000, 2000, 以此类推
- 第一个报文段有从0开始的数据,第二个是从1000开始
确认号:主机A填充进报文段的序列号是A期望从B收到的下一字节的序列号
累积确认(cumulative acknowledgement): 只确认该流中第一个到丢失字节为止的字节。
- 为保证可靠性,能完整重建数据
Example:
- A: Seq=42, Ack=79, data='C' - B: Seq=79, Ack=43, data='C' - A: Seq=43, ACK=80
- 起始Sequence:客户端发送第一个报文段序号为42, 服务器发送第一个序号为79。
- 第一个包:客户将向服务器发送第42字节,期望从服务器获得第79号字节
- 第二个包:确认已经收到用户42号字节以及之前的内容, 期待第43号字节的出现,序号79为服务器要发送的第一个字节
- 第三个包:序列号表明将向服务器发送第43号字节,确认号表明确认已经收到字节流第79号及以前的字节,正在等待第80号出现
往返时间估计与超时
RTT 往返时间, 数据来回一次用的时间
估算:取样(Sample RTT) 注意:不会为重传包计算RTT值(猜想:有可能马上收到相应ACK,若计算会使估计值偏小)
计算方式:Exponential Weighted Moving Average移动指数平均(EWMA)
EstimatedRTT = (1-alpha)*EstimatedRTT + alpha*EstimatedRTT
偏差值计算
DevRTT = (1-beta)*DevRTT + beta*|SampleRTT - EstimatedRTT|
超时区间
TimeoutInterval = EstimatedRTT + 4 * DevRTT
快速重传
- duplicate ACK 冗余ACK, 再次发送确认
- 具体方法
- 正常接收前面的数据, 但延迟, 等待后重传
- 带有比期望序号大的SEQ(序列号)的包出现,有一定间隔, 立即重传
- 部分填充间隔的包出现, 如果起始于间隔的低端,则立即发送ACK (正确接收的数据到本包为止,以此为基础发送)
- 3个duplicate ACK(接收了对方传来的三个相同ACK)
- 确认在本报文段之后的数据已经丢失,快速重传
- 原理
- https://www.zhihu.com/question/21789252
流量控制, 拥塞控制
- 发送方维护接收窗口 receiver window -> 接收方还有多少缓存空间
- 保证缓存不溢出则,上一个读取的字节号和上一个接收的字节号之差不得大于缓存容量
- rwnd跟踪缓存剩余量,即缓存总量减去上述两个字节号之差
- 特殊情况:
- rwnd = 0
- B发送rwnd=0之后如果不再发送请求,则A认为B缓存满,将不会主动发送信息,但实际上这之后B的缓存清空了,则导致A被阻塞
- 解决:B中接收窗口为0时,A将继续发送只有一个字节数据的报文段,直到缓存清空。rwnd != 0
- rwnd = 0
拥塞控制
在一个发送方中未被确认(被对方确认,即收到了对方对于该数据的ACK)的数据量不能超过cwnd和rwnd中的最小值
LastByteSent - LastByteAcked <= min{cwnd, rwnd}
TCP Reno
慢启动:
- cwnd = MSS
- 初始发送速率:MSS/RTT
- 每当报文段首次被确认就增加一个MSS
- 每过一个RTT, 发送速率*2(每一个正确接收的包都将导致速度增加一个MSS), 指数增长
丢包时间 -> cwnd = 1, 慢启动
ssthreash
慢启动阈值 = cwnd/2- 超过本阈值,结束慢启动,并开启拥塞避免
- 三个重复ACK,结束慢启动,快速重传,快速恢复
避免方法
- 通过阈值,每个RTT只将cwnd值增加一个MSS
- 实现:每收到一个包,将速率增加1/cwnd * MSS
- 超时的包:cwnd = 1, 丢包事件:ssthreash = cwnd/2
快速恢复
- 对于每个收到的重复ACK,cwnd += MSS, 当丢失文段的ACK到达时, TCP在降低cwnd后进入拥塞避免状态
- 出现超时事件:cwnd = 1, 慢启动
- 丢包: cwnd = MSS, ssthresh = cwnd/2
- 对于每个收到的重复ACK,cwnd += MSS, 当丢失文段的ACK到达时, TCP在降低cwnd后进入拥塞避免状态