- 协议总览
- TCP / UDP
- TCP握手和挥手
- 三次握手
- 四次挥手
- 常见问题
- TCP的11种状态
- 如何保证可靠性
- ACK和SEQ:保证有序
- CheckSum:保证不出错
- 超时重传:丢失后重传
- 流量控制:防止发送过快,接收者来不及接收——>滑动窗口机制
- 拥塞控制:防止过多数据注入网络出现网络负载过大
- 慢开始,拥塞避免
- 快重传,快恢复
1. 五/七层模型
- 五层协议的体系结构主要包括:应用层、运输层、网络层,链路层,物理层。
- OSI七层协议模型主要包括是:应用层(Application)、表示层(Presentation)、会话层(Session)、运输层(Transport)、网络层(Network)、链路层(Data Link)、物理层(Physical)。
- 五层协议
- 应用层:HTTP/HTTPS,SMTP(电子邮件),FTP(文件传输),DNS(域名解析)
- 传输层:TCP,UDP
- 网络层:IP,ARP(将网络层地址转换为链路层地址)
- 链路层:Ethernet,PPP,IEEE 802.11(无线局域网协议,也称为Wi-Fi)
- 物理层:负责在物理媒体上传输比特流
2. TCP / UDP
UDP | TCP | |
是否连接 | 无连接,减小开销和发送数据的延迟 | 面向连接,需要先握手 |
是否可靠 | 不可靠:尽最大努力交付,不需要维持复杂的连接状态表 | 可靠:无差错,不丢失不重复,按序到达 |
连接对象个数 | 支持一对一,多对一,一对多 | 只支持一对一(点对点): 通信双方能在任何时候彼此发送数据,两端都设有发送缓存和接受缓存 |
传输方式 | 面向报文 | 面向字节流:把应用层交付的数据看作无结构的字节流 |
首部开销 | 8字节 | 20字节 |
场景 | 实时应用(IP电话,视频会议,直播等) | 可靠传输(文件传输) |
运行在TCP的协议:
HTTP(Hypertext Transfer Protocol,超文本传输协议)
,主要用于普通浏览。HTTPS(HTTP over SSL,安全超文本传输协议)
,HTTP
协议的安全版本。FTP(File Transfer Protocol,文件传输协议)
,用于文件传输。POP3(Post Office Protocol, version 3,邮局协议)
,收邮件用。SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)
,用来发送电子邮件,很多邮件服务器都是这个协议。TELNET(Teletype over the Network,网络电传)
,通过一个终端(terminal)
登陆到网络。SSH(Secure Shell,用于替代安全性差的TELNET)
,用于加密安全登陆用。
运行在UDP的协议:
DNS(Dynamic Name Service,域名服务)
,将主机名解析成IP地址。DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)
,动态配置IP地址。
2.1 TCP
- 序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
- 确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1
- 保留字段:供以后使用,暂时为0
- 标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
- ACK:ACK=1时,确认号才有效,ACK=0时无效
- FIN:FIN=1时,表示发送端的数据已经发送完毕,释放连接
- PSH(push):PSH=1时,TCP会尽快交付给应用程序而不再等到缓存填满再交付
- RST(reset):RST=1时,表明连接中出现严重差错,应重新连接
- SYN:SYN=1时,表示这是一个连接请求或连接接受报文
- URG:当URG=1时,紧急指针(urgent pointer)有效
- 允许对方发送的数据量
2.2 UDP
- 计算校验和需要在UDP数据报之前增加12字节的伪首部。
- 伪首部仅仅是为了计算校验和,不向下传送也不向上递交。
- 这样的校验和,既检查了UDP数据报,又对IP数据报的源IP地址和目的IP地址进行了检验。
- 伪首部供12个字节
3. TCP三次握手和四次挥手
- 一个TCP连接由一个4元组构成,分别是两个IP地址和两个端口号
(1)三次握手
- 三次握手的本质是确认通信双方收发数据的能力
- 第一次握手:测试客户端的发送能力和服务端的收件能力
- 第二次握手:客户端发送能力和服务端的收件能力得到肯定;开始测试客户端的收件能力和服务端的发件能力
- 第三次握手:客户端的收件能力和服务端的发件能力得到肯定。握手成功
- 第一步:客户向服务器:SYN=1(表示这是一个建立连接请求),序号seq=x(随机)
- 第二步:服务器向客户:SYN=1,ACK=1,seq=y(随机),ack=x+1
- 第三步:客户向服务器:ACK=1,seq=x+1(第一次握手时发送报文是占据一个序列号的,所以这次seq就从x+1开始,需要注意的是不携带数据的ACK报文是不占据序列号的,所以后面第一次正式发送数据时seq还是x+1),ack=y+1
- 四次挥手的目的是关闭一个连接
- 比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。
- 第一步:客户向服务器:FIN=1(释放连接请求),seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外FIN报文段即使不携带数据也要占据一个序列号。
- 第二步:服务器向客户:ACK=1(确认收到),ack=1102,seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
- 第三步:服务器向客户:FIN=1,ACK=1,ack=1102,seq=2350(2300+50)。服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文
- 第四步:客户向服务器:ACK=1,,ack=2351,seq=1102。注意客户端发出确认报文后不是立马释放TCP连接,而是要经过2MSL(最长报文段寿命的2倍时长)后才释放TCP连接。而服务端一旦收到客户端发出的确认报文就会立马释放TCP连接,所以服务端结束TCP连接的时间要比客户端早一些。
(3)常见面试题
(3.1)为什么TCP连接的时候是3次?4次不可以吗?
1.1 A发送 SYN + seq(X)给B
1.2 B回复 ACK + ack(X+1),记录X到本地
1.3 B发送 SYN + seq(Y)给A
1.4 A回复 ACK +seq(X+1) + ack(y+1),记录Y到本地
其中1.2和1.3可以合并为一步,四步冗余了。
(3.2)为什么TCP连接的时候是3次?2次不可以吗?
1.1 A发送 SYN +seq(X)
1.2 B回复 SYN + seq(Y) + ack(X+1)
B无法知道A是否收到了,如果第二封丢失了,B认为连接已经开启,A认为没有开启并且不知道B的seq(Y)。所以需要A再给B回复确认自己已经收到。
(3.3)三次握手丢包情况
第一个包丢失,B没收到:A会周期性超时重传,直到收到B的确认
第二个包丢失,A没收到:B会周期性超时重传,直到收到A的确认
第三个包丢失:A发完包会单方面认为连接建立,B却不知情
a.双方都没有数据发送:B会超时重传,直到收到A的确认
b.A有数据发送,B收到之后自动开启连接
c.B有数据发送:数据发送不了,因为B不知道是否建立连接。会一直超时重发第二个包直到收到连接建立的确认
(3.4)如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
(3.5)挥手时为什么第四次回收的确认报告要等到2MSL才释放连接?
这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认ack报文就会重发第三次挥手的报文,这样报文一去一回最长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。
4. TCP的11种状态
5. TCP如何保证传输的可靠性
(1)确认应答和序列号(ACK和SEQ):合理分片,保证重排序和丢弃重复数据
- 序列号SEQ:TCP传输时将每个字节的数据都进行了编号,这就是序列号
- 确认应答ACK:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发
- 序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序(传输过程可能顺序会乱),并且去掉重复序列号的数据
- 反观UDP:IP数据报大于1500字节,大于MTU.这个时候发送方IP层就需要分片(fragmentation).把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组.这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便无法重组数据报.将导致丢弃整个UDP数据报.
(2)校验和
- TCP将保持它首部和数据的检验和。这是一个端到端的检验和。目的是检测数据在传输过程中的任何变化。
- 如果收到的段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。(不给出响应,超时重传)
(3)超时重传
- TCP发出一个报文段后,启动定时器,如果没收到关于这个报文段的回复确认,将重发这个报文段
(5)流量控制
- 现象:如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失
- 解决方案:流量控制,为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制
- 具体实现方法:滑动窗口机制
- 滑动窗口可能出现的问题:死锁。当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁
- 解决方法:为了避免流量控制引发的死锁,TCP使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生
当窗口值为0,而接受方把窗口值恢复(比如ACK=1,ack=601,rwnd=200),但确认丢失,进入相互等待的死锁局面。所以如果窗口值为0,发送端就会开启一个持续计数器,每个一段时间询问一下接收方。
(6)拥塞控制
- 现象:拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况;常用的方法就是:( 1 )慢开始、拥塞避免( 2 )快重传、快恢复。
(6.1)慢开始+拥塞避免(1988年提出)
- 慢开始:不要一开始就发送大量的数据,先探测一下网络的拥塞程度,由小到大逐渐增加拥塞窗口的大小。
- 拥塞避免:发送窗口>慢开始门限(16) 时:每次+1,而不是双倍增加;直到出现丢包,重新慢开始
(6.2)快重传,快恢复(1990年新增改进,有时个别报文段丢失,并非因为拥塞)
- 快重传:快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方,可提高网络吞吐量约20%)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
- 快恢复:当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半(为了预防网络发生拥塞)。但是接下去并不执行慢开始算法
- 考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh减半后的值,然后执行拥塞避免算法,使cwnd缓慢增大。