##包头结构
ip层数据包结构
<–Ethernet–><–IP–><–TCP–><–DATA–>
<–Ethernet–><–IP–><–UDP–><–DATA–>
以太网数据包1522字节固定包长,其中22字节以太网包头,1500的负载。IP层固定包头20,剩1480数据负载。tcp包头最少20,所以最大数据负载1460,但是一般会包含其他包头信息,所以数据大概在1400字节左右。
###tcp包头结构
源端口(16bits) | 目标端口(16bits) |
---|---|
序列号(32bits) | |
确认序列号(32bits) | |
包头长度(4bits)+保留(4bits)+状态位cwr(1bit)+ECE+URG+ACK+PSH+RST+SYN+FIN | 窗口大小(16bits) |
校验和(16bits) | 紧急指针(16bits) |
选项(32bits) |
###udp包头结构
源端口(16bits) | 目标端口(16bits) |
---|---|
长度(16bits) | |
校验和(16bits) |
- 源端口:包含了发送方应用程序对应的端口。
- 目标端口:包含了接收方程序对应的端口。
- 序列号:程序接收端通过该序号识别数据包是否重复,并依靠该字段对数据进行排序,进而对应用层提供有序的数据流。
- 应答序列号:用于确认之前收到的数据包,并准备接收此序列号的数据包,根据之前处理包的序号+包长推断。
- 包头长度:指明tcp包头长度。 保留:
- 8位标记位:
CWR(Congestion window Reduce):拥堵窗口减少标记。用它来表明在接收到设置ECE标记的tcp包,并在接收到消息之后通过降低发送窗口大小来降低发送速率。
ECE(ECN Echo):ECN响应标记位用来在TCP3次握手时表明这个TCP端具备ECN功能。在数据传输过程中用来表明接收到的TCP包ip头的ECN被设置为11,这时网络线路拥堵。
URG(Urgent):该标记位表示紧急标记有效。
ACK:该位为1表示是个ack确认包,否则不是
PSH(push):该标记位表示,发送缓存中已经没有待发送的数据,接收端不该将数据进行队列处理,而是尽可能快的将数据由应用层进行处理。
RST(reset):用于reset相应的tcp连接,通常发生在异常或错误的时候。
SYN:同步序列编号,只在握手的时候用到。
FIN(finish):发送端主动断开,不再发送数据。但还能接收。 - 窗口大小:指明了当前接收端窗口的大小,用于控制tcp流量控制。
- 校验位:发送端基于数据内容计算的一个数值,接收端根据这个来检验数据传输过程有无错误。
- 紧急指针:指向后面是有限数据的字节,在rug位标记的时候才有效。
- 选项:长度不定,但必须是32bits的整数倍,常见的选项包括MSS,ASCK,Timestamp等。
PS:
一般情况携带数据的包会以psh+ack来作为标记,但是不同TCP协议栈解释不大一样,有些携带数据的包只会带ack标记,这样的坏处在于会混淆接收方对包做出正确响应,TCP协议默认delay_ack,就是延迟ack响应,tcp在接收到数据包的时候会检查是否需要发送ack,需要的话会检查进行快速ack还是延迟ack
确认条件:
1、当有数据发送的时候,ack会随着数据一块发送
2、当没有数据的时候,ack会有一个延迟,等待是否有数据一块发送,延迟时间一般在40ms左右,如果等待时间内有数据发送,ack会随着数据一起发送,如果没有会在超时时间到来的时候单独发送ack包不携带数据。这里的延迟指的是内核会启动一个定时器,每隔一定时间会进行一次检查。
3、如果在等待发送ack期间,第二个数据到来了,这时需要立刻发送ack。
延迟发送的优缺点:
优点:减少了数据段发送个数,提高了效率
缺点:过多的delay ack会拉长RTT
回到上面话题,如果有的协议栈会以ack的包来代替psh ack,而接收端进行delay ack,会造成发送端以为数据超时未响应而进行重复发送。…
解决方法,linux下需要在recv执行之后,设置快速ack响应。win需要设置注册表里的快速ack响应时间。
##TCP状态图
##TCP滑动窗口–流量控制机制
TCP的窗口机制有两种,1种是固定窗口大小,另一种是滑动窗口。这个窗口指的是我们数据发送数据的大小,以字节为单位。发送接收方都维系着这样一个窗口,数据只有落在窗口内才能够被发送和接收。TCP滑动窗口通过改变窗口大小来调节两个主机之间的数据传输速度。TCP支持双工数据传输,因此TCP有两个TCP滑动窗口,一个用于接收,一个用于发送。TCP使用确认技术,确认号指的是下一个希望获取的字节序号,同时会携带窗口号大小,告诉发送方本次期望接收到数据的大小。原理介绍
每个tcp报文都包含ack号和窗口通告消息,发送端可以据此来改变窗口大小,窗口的左边界不能左移,因为它控制的是已经确认的ack号,具有积累性,不能返回。当得到的ack号增加,而窗口大小不变,这时窗口向前滑动。当ack号变大,而窗口变小,这时左右边界距离变小,当左右边界相等时,称为零窗口,这时不能再发送新的数据,这时tcp发送端开始探测对方窗口。
同发送端一样,接收端也维护了一个左边界,一个右边界,当达到数据的序号小于左边界就丢弃,大于右边界也丢弃,只有当接收到的序号等于左边界才正常接收,然后窗口向前滑动。
所以一般发送窗口的大小由接收窗口大小决定
结论:接收窗口大小由应用层取数据速度决定,如果应用层来不及取数据,则接收缓存会填满,则窗口为0.所以应用层读数据越快,接收窗口越大(传输效率越高).连接有代码级的解释说明
##TCP拥堵控制
###慢启动:
服务端发送数据当然是越快越好,但是因为网络状况不确定,发送速度太快,带宽小,路由器过热,缓存溢出等许多因素都会导致丢包,线路不好,发的越快丢的越多。
TCP协议为了做到效率与可靠性的统一,设计了一个慢启动机制,开始的时候发生较慢,然后根据丢包状况来来调整发送速率:如果不丢包就加快速率,丢包就降低速率。
ack 携带了两个信息:
期待下一个数据包的编号
接收方接收窗口的大小。
慢启动
###数据包丢失处理
tcp包发送的时候会携带一个包序号,接收端会根据包序号推断下一个期待接收到的包的序号,用ack响应到发送端,如果一直没有收到这个包而收到了其他序号的包,这时ack的响应一直是原来的序号,发送端如果接收到连续三个重复ack,或者超时没有收到ack,就会确认当前包丢失,从而再次发送这个包。通过这个机制TCP保证了不会有数据的丢失。
###快重传和快恢复
快重传和快恢复理论
如果发送方设置的超时时间已到但是还没收到确认,那么很有可能出现了堵塞,导致报文丢失,这时TCP会把窗口减少到1
快重传首先要求接收方在收到一个失序的报文后立即发出重复确认,而不是等到自己发数据的时候才捎带确认目的是为了尽早告知对方有数据丢失。
快重传还规定:发送方只要收到三个重复确认就应当立即重传尚文收到的报文,而不必等待超时重传到期。所以需要接受方在收到发送方发送的乱序报文后立即回复缺失报文的响应ack。
###TCP状态机
TCP状态描述如下
状态 | 描述 |
---|---|
LISTEN | 服务端启动端口,等待远端TCP客户端进行连接 |
SYN_SENT | 发送请求连接后,等待来自服务端的确认,TCP第一次握手后客户端所处的状态 |
SYN-RCVD | 服务端接收到连接请求,端点正在等待最终确认,TCP第二次握手后服务端状态 |
ESTABLISHED | 连接建立完成,双反进行正常通信。三层握手进行完成后双方状态 |
FIN_WAIT_1 | 等待来自远端的TCP断开请求或者终止请求的确认 |
FIN_WAIT_2 | 发送断开请求后,等待远端关闭请求 |
CLOSE_WAIT | 端点收到来自远端的关闭请求,tcp正在等待本地应用的断开请求 |
CLOSING | 等待远端的TCP连接断开请求确认 |
LAST_ACK | 等待 |
TIME_WAIT | 等待足够的时间来确保TCP接收到其连接终止请求的确认 |