三. 传输层
1. TCP协议
1.1 什么是TCP协议
TCP(Transmission Control Protocol)传输控制协议,是传输层一种面向连接的,可靠的,基于字节流的协议,用来保证数据的可靠传输.
TCP位于应用层跟网络层之间,保证应用数据成功在网络之间的可靠传输.
TCP并不能保证数据一定会被对方接收到,因为这是不可能的,如果有可能,就把数据传递给对方,实在没办法就放弃重传并且终端连接来通知用户,因此TCP并不是100%可靠的协议,它提供的是数据的可靠递送或故障的可靠通知.
那么TCP是如何保证数据传输的可靠性呢?
1.2 TCP数据包的大小
一个以太网数据包的大小固定为1522个字节;
1522 = 22(以太网Head) + 20(IP Head) + 20(TCP Head) + 1460(Data)
其中Data大小被称为TCP数据包的负载,因此TCP数据包最大负载是1460个字节,但是由于IP和TCP协议往往有额外的Head信息,所以实际负载在1400字节左右.
1.3 TCP数据包编号
由于TCP一个数据包的负载大小是有限的(1400bit左右),那么一次性发送大量数据,比如10M的文件,就需要分包,为了方便接收方还原或者丢包的时候知道丢失是哪个包,
除了第一个包是随机数以外,后面每个包的编号都是前面一个包的编号+负载大小,比如一号包是1,包的负载是100个字节,那么紧接其后的二号包编号应该是101.为了保证可靠性,每个数据包都有自身编号,和下一个包的编号,这样接收方就可以如链表一般得到一个完整的数据包了,而且一旦数据大小对不上两个包编号的差,就能快速定位问题了.
对于分包组装来说,就是操作系统做的事情了,应用程序拿到的必定是操作系统组装好的完整10M数据包,对于操作系统来说,他做的也就是从第一个数据包开始,如同链表的顺序访问一般,按照下一个数据包编号把所有数据包组合好,然后按照TCP数据包里面的port参数,发给不同的应用程序,比如TCP数据包里面的port是80,而80端口是web服务复制监控的,web服务就会把数据包给到浏览器应用程序.
1.4 慢启动和ACK
服务器发送数据包,当然越快越好,最好一次性全发出去。但是,发得太快,就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话,发得越快,丢得越多。
慢启动指的是服务器发送数据包的时候,由于事先不知道线路的理想速率,在刚开始的时候发的较慢,如果不丢包,就加快发送速度,如果丢包就降低发送速度.
Linux 内核里面设定了(常量TCP_INIT_CWND
),刚开始通信的时候,发送方一次性发送10个数据包,即"发送窗口"的初始大小为10。然后停下来,等待接收方的确认,再继续发送。
这种慢启动再由线路接受速率的操作是怎么做到的呢? 答案是ACK
默认情况下,接收方每收到两个数据包,就要发送一个确认"ackonwledgement"消息,简称ACK.
ACK携带两个消息
- 期待收到的下一个数据包的编号(用来告诉服务器自己本包收到了多少数据)
- 接收方的接收窗口缓存剩余(告诉服务器注意别发太快以免自己接收不过来)
服务器收到ACK信息,就可以推测接收方大概的网速,从而调整发送速率,调整好之后的固定速度,就是"发送窗口"的正常大小,该大小是可变的.
即便接收方带宽再高,TCP也总从10个数据包开始慢慢测试,过一段时间才达到最高传输速率,这就是整个慢启动.
1.5 快重传和快恢复
快重传算法要求接收方每收到一个失序的报文就立即发送重复确认,而不是等到自己发送数据时才确认;
假如正确情况下,接收方应该收到Msg 1~4这四个报文,实际上收到Msg 1,Msg 3,Msg4,当收到Msg3的时候,接收端发现失序,立刻发送Msg1的序列号跟服务器确认,服务器收到立刻恢复到Msg1 开始重传,而不用等到发完四个包再重传,这一机制提高了网络的吞吐量.
1.6 TCP连接建立时的三次握手
模拟情景:
卢本伟: 听得到我说话吗?老,老铁(发出SYN=1,等待确认seq=x)
队友: 听得到(自己听到的消息是ACK=1,SYN=1),你听得见我说话吗(发送Ack=1,seq=y)
卢本伟: 我听得到(ACK=1),兄弟(Seq=x+1,Ack=y+1)
之后卢本伟开始跟队友聊自己的背包平底锅…
- 客户端向服务器发送SYN=1请求,seq为x(SYN=1表示尝试建立连接)
- 服务器收到并同意建立连接(ACK=1),向客户端发送SYN=1(服务器尝试向客户端建立连接),序列号为y,为了表示自己收到了seq,还要回复Ack=seq+1
- 客户端同意建立连接(ACK=1),表示收到服务器端的确认号 Ack,并将其值作为自己的序号值(Seq=x+1),还要告诉对方自己收到了对方的序列号(Ack=y+1)
当服务器端收到来自客户端确认收到服务器数据的报文后,得知从服务器到客户端的数据传输是正常的,从而结束 SYN-SEND 阶段,进入 ESTABLISHED 阶段,从而完成三次握手。
常见问题汇总
第一次握手失败会发生什么?
服务器没收到SYN=1,则不会做出任何回应,此时客户端请求重连,重连次数超过最大重传次数,会报错返回-1;
第二次握手失败会发生什么?
若第二次握手客户端未接收到服务器回应的 ACK 报文时,客户端会采取第一次握手失败时的动作,这里不再重复,而服务器端此时将阻塞在 accept() 系统调用处等待 client 再次发送 ACK 报文
第三次握手失败会发生什么?
服务器会跟客户端一样失败重传,若超过重传次数,accept()系统调用返回-1,服务端连接建立失败.
如果两次握手会怎么样?
第二次握手后就建立连接的话,此时客户端知道服务器能够正常接收到自己发送的数据,而服务器并不知道客户端是否能够收到自己发送的数据。
1.7 TCP连接关闭时的四次挥手
- 客户端向服务器发起请求(FIN=1)请求断开连接,并发送序列号Seq=u,自身从
ESTABLISHED
进入FIN-WAIT-1
- 服务器收到FIN=1的请求断开连接报文后,结束
ESTABLISHED
阶段,进入CLOSE-WAIT
(等待上层程序确认没有未发的数据)阶段,做好了释放连接准备后,发送报文给客户端,告知对方自己已经收到客户端的关闭连接请求,并让对方再等等,发送报文包括- ACK=1,收到客户端的FIN=1请求
- 确认号为Ack=u+1,表示在已经收到服务器报文的基础上,将其序列号加1作为本段报文确认好Ack的值
- 序列号为Seq=v
- 服务器确认没有未发完的内容之后,向客户端发送请求FIN=1请求断开连接,标记位是1,序列号是w,Ack=u+1
- 客户端回复ACK=1表示已经收到,Seq=u+1,将对方的Ack确认消息当做自己的序列号,并且确认号Ack为w+1,然后自己进入
TIME-WAIT
等待两个MSL((Maximum Segment Lifetime)时间,如果没有收到服务器的消息,则客户端CLOSE,服务器收到此消息之后 也CLOSE连接,至此TCP连接关闭.
2. UDP协议
2.1 什么是UDP协议
UDP(User Datagram Protocol) 用户数据包协议是一种无连接
,面向报文
的传输协议.与TCP互为补充,UDP不保证传输的可靠性,只尽最大能力交付报文,所以主机不需要维持复杂的连接状态表,除此之外,UDP没有拥塞控制
,不会因为网络拥塞,影响服务器的传送速度.
2.2 UDP跟TCP协议的区别
协议 | 是否面向连接 | 传输可靠性 | 传输形式 | 传输效率 | 所需资源 | 头部字节 | 应用场景 |
---|---|---|---|---|---|---|---|
TCP | 是 | 可靠 | 字节流 | 慢->稍快 | 多 | 20~60 | 文件传输,邮件传输 |
UDP | 否 | 不可靠 | 数据报文段 | 快 | 少 | 8 | 即时通信 |