TCP/IP网络模型:计算机和网络设备通讯、需要保证双方基于相同的方法
TCP/IP协议族: TCP UDP IP FTP ICMP
OSI七层模型和TCP/IP四层模型比较:
TCP:是面向链接、可靠的、基于字节流的传输层通信协议
三次握手:
四次挥手:
那么经典问题来了
1、为什么需要三次握手,两次行不行?四次行不行
先回答,两次行不行问题,1、造成资源浪费。 client向server 发送数据包后,因为网络问题导致丢失延迟很长时间,此时,client会认为已经丢失,会再次发送一个请求包,如果正常传输,server会返回一个确认包,连接建立,但是,第一次传的包也达到了server,进行确认,clinet再次收到因为认为已经丢失,不再处理,server却会保持这周僵尸连接,这就造成了资源浪费2、在server 端读取到收到的请求包后,就开发发送数据,但是server的应答传输丢失了,client 长时间未收到数据,会导致重新请求,但是server 在发送后,发送数据超时后,会重复发送,导致死锁
三次可以相互确认,规避这种问题
再回答四次不可以的问题: 三次握手已经确认相互建立连接,第三次可以开始携带数据了,如果增加第四次,增加确认环节,并不能优化确认的
四次挥手为什么要等待3MSL
MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值
第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。
第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文
。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
最后聊下time_wait:
发起端调用close函数,在发送最后一个ack,进入time_wait,发送端会等待2MSL然后返回初始状态,这个状态就是time_wait
1、实现全双工的可靠释放
2、使旧的数据包过期而消失
如何避免:
服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。在一个非常有用的场景就是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。
为何要设置time_wait:
1、确保发送端的最后一个ack到达接收端
2、发送端发送完后经过2MSL,使产生的报文从网络消失
TCP和UDP 区别:
UDP | TCP | |
---|---|---|
是否连接 | 无连接 | 面向连接 |
是否可靠 | 不可靠传输,不使用流量控制和拥塞控制 | 可靠传输,使用流量控制和拥塞控制 |
连接对象个数 | 支持一对一,一对多,多对一和多对多交互通信 | 只能是一对一通信 |
传输方式 | 面向报文 | 面向字节流 |
首部开销 | 首部开销小,仅8字节 | 首部最小20字节,最大60字节 |
适用场景 | 适用于实时应用(IP电话、视频会议、直播等) | 适用于要求可靠传输的应用,例如文件传输 |
TCP 如何确保可靠连接:
1、序列号、确认应答、超时重传
可靠技术:
超时重传:
超时确认
- RTT(Round Trip Time):往返时延,也就是数据包从发出去到收到对应 ACK 的时间。RTT 是针对连接的,每一个连接都有各自独立的 RTT。
- RTO(Retransmission Time Out):重传超时,也就是前面说的超时时间。
RTO 是比RTT 略大,有计算公式,会根据后续的RTT来变化,如果重传依旧出现超时。Linux做法是加大一倍
快速重传:无序的报文段,通过连续收到三个或者以上重复的ack,那么这个报文段就丢失了,需要重传。
超时重传只是解决超时问题,不能解决重传哪一个的问题
SACK方法:在TCP 头部新增一个sack 字段,用来存储需要传输的包地图发送给 发送方,如此发送方就知道哪些包没有收到就可以采取重传操作了
Duplicate SACK 又称 D-SACK
,其主要使用了 SACK 来告诉「发送方」有哪些数据被重复接收了。
1)可以让发送方知道,是发出去的包丢了,还是回来的ACK包丢了。
2)是不是自己的timeout太小了,导致重传。
3)网络上出现了先发的包后到的情况(又称reordering)
4)网络上是不是把我的数据包给复制了。
发送数据: 滑动窗口和流量控制
TCP 发送接收机制是当发送完一个数据,就回复一个数据,当发送方接受到回复后,再发送下一个,但是效率太低,主要是往返时间过高的问题会导致延迟
引入窗口概念可以提高效率,滑动窗口是用来处理解决流量控制的手段,发送端和接收端分别维护一个发送窗口和接收窗口。
首先,接收端告诉发送端 可以接收的窗口大小。控制发送的速度,
发送端只有收到接收端得ack确认后,才会移动发送窗口的左边界
接收端只有前面的段数据接收后才会移动左边界,前面还有数据并未接收,但是后面数据以及接收了,窗口不会移动,确保对未接收的数据进行数据重传
TCP的标准窗口最大为2^16-1=65535个字节
拥塞处理四种算法:
1、慢启动:
1)连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。
2)每当收到一个ACK,cwnd++; 呈线性上升
3)每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
4)还有一个ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”(后面会说这个算法)
2、拥塞避免:一般来说ssthresh的值是65535,单位是字节 if cwnd >= ssthresh
1)收到一个ACK时,cwnd = cwnd + 1/cwnd
2)当每过一个RTT时,cwnd = cwnd + 1
3、拥塞发生:
1)等到RTO超时,重传数据包。TCP认为这种情况太糟糕,反应也很强烈。
-
- sshthresh = cwnd /2
- cwnd 重置为 1
- 进入慢启动过程
2)Fast Retransmit算法,也就是在收到3个duplicate ACK时就开启重传,而不用等到RTO超时。
-
- TCP Tahoe的实现和RTO超时一样。
-
- TCP Reno的实现是:
- cwnd = cwnd /2
- sshthresh = cwnd
- 进入快速恢复算法——Fast Recovery
- TCP Reno的实现是:
4、快速恢复:快速恢复算法是认为,你还有3个Duplicated Acks说明网络也不那么糟糕,所以没有必要像RTO超时那么强烈
进入Fast Recovery之前,cwnd 和 sshthresh已被更新:
- cwnd = cwnd /2
- sshthresh = cwnd
然后,真正的Fast Recovery算法如下:
- cwnd = sshthresh + 3 * MSS (3的意思是确认有3个数据包被收到了)
- 重传Duplicated ACKs指定的数据包
- 如果再收到 duplicated Acks,那么cwnd = cwnd +1
- 如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了
IP头协议号:
1 ICMP 2 IGMP 6 TCP 17 UDP 88 IGRP 89 OSPF
TCP 头部:
UDP 的connect 函数:
1、调用connect 函数,只是检查已知错误
2、不用指定目的ip和端口
3、不必使用recvfrom以获悉数据报的发送者,而改用read、recv或recvmsg
4、由已连接UDP套接字引发的异步错误会返回给它们所在的进程,而未连接的UDP套接字不接收任何异步错误
重复connect 函数只会指定新的connect
参考文献:
TCP滑动窗口
TCP重传机制
UDP连接调用connect()函数
TIME_WAIT 状态
图解TCP