文章目录
传输层>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.
UDP
协议端格式
- UDP报头8byte,其中有16位的UDP长度,也就是说UDP最大长度为64KB
- 校验和,为了发现UDP/TCP首部和数据在发送端到接收端之间发生的任何改动。如果接收方检测到检验和有差错,则UDP/TCP段会被直接丢弃。
无连接,不可靠,面向数据报。
- 无连接: 知道目标的IP和目标端口号就直接进行传输, 不需要建立连接;
- 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息;
- 面向数据报: 不能够灵活的控制读写数据的次数和数量;应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并。
注意:UDP能传输的数据最大长度是64K(包含UDP首部8byte),如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。
TCP(传输控制协议)
-
序号,TCP将每个字节的数据都进行了编号. 即为序列号.每一个ACK都带有对应的确认序列号。
-
4位报首长度:报首有多少个32位bit(4字节),TCP报首最大长度为15*4=60;
-
标志位:URG-紧急指针是否有效;ACK-确认号是否有效;PSH-提示接收端立即从缓冲区将TCP数据读出;RST-重新建立连接标志位复位报文段;SYN-请求建立连接同步报文段;FIN-通知对方,本端关闭结束报文段
-
TCP 是面向字节流的,通过 TCP 传送的字节流中的每个字节都按顺序编号,而报头中的序号字段值则指的是本报文段数据的第一个字的序号。
确认应答(ACK)机制
- TCP将每个字节的数据都进行了编号. 即为序列号.每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发.
超时重传机制
- 主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发;
超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.如果重发一次之后, 仍然得不到应答, 等待 2500ms 后再进行重传.如果仍然得不到应答, 等待 4500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接。
补充:主机A未收到B发来的确认应答,若是因为ACK丢失,主机B会收到很多重复数据. 那么TCP协议利用前面提到的序列号能够识别出那些包是重复的包, 并且把重复的丢弃掉,做到去重的效果。
连接管理机制
- 在正常情况下, TCP要经过三次握手建立连接, 四次挥手断开连接。
TIME_WAIT状态(请求方)
TCP协议规定,主动关闭连接的一方要处于TIME_ WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态。
MSL是TCP报文的最大生存时间, 因此TIME_WAIT持续存在2MSL的话就能保证在两个传输方向上的尚未被接收或迟到的报文段都已经消失同时也是在理论上保证最后一个报文可靠到达。
CLOSE_WAIT 状态(接收方)
进入CLOSE_WAIT后说明被动方准备关闭连接(需要处理完之前的数据); 当被动方真正调用close关闭连接时, 会向主动方发送FIN, 此时被动方进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是主动方确认收到了FIN)。
滑动窗口
起因:每一个发送的数据段, 都要给一个ACK确认应答. 收到ACK后再发送下一个数据段,这样做有一个比较大的缺点, 就是性能较差. 尤其是数据往返的时间较长的时候。
- 那么一次发送多条数据, 就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了),这便是滑动窗口。
补充:窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 若窗口大小是4000个字节(四个段).发送前四个段的时候, 不需要等待任何ACK, 直接发送;收到第一个ACK后, 滑动窗口向后移动, 继续发送第五个段的数据; 依次类推;操作系统内核为了维护这个滑动窗口, 需要开辟发送缓冲区来记录当前还有哪些数据没有应答; 只有确认应答过的数据, 才能从缓冲区删掉;窗口越大, 则网络的吞吐率就越高;
若发送失败,利用开辟的缓冲区可以实现"高速重发控制"(也叫 “快重传”).
流量控制
- 接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送,就会造成丢包, 继而引起丢包重传等等一系列连锁反应.因此TCP支持根据接收端的处理能力, 来控制发送端的发送速度. 这个机制就叫做流量控制(Flow Control);
补充:接收端将自己可以接收的缓冲区大小放入TCP首部中的 “窗口大小” 字段, 通过ACK端通知发送端;窗口大小字段越大, 说明网络的吞吐量越高;接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端.
拥塞控制
起因:虽然TCP有了滑动窗口这个大杀器, 能够高效可靠的发送大量的数据. 但是如果在刚开始阶段就发送大量的数据, 仍然可能引发问题.因为网络上有很多的计算机, 可能当前的网络状态就已经比较拥堵. 在不清楚当前网络状态下, 贸然发送大量的数据,
是很有可能引起雪上加霜的.
- TCP引入慢启动机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据;
补充:拥塞窗口增长速度, 是指数级别的. “慢启动” 只是指初使时慢, 但是增长速度非常快,为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍.此处引入一个叫做慢启动的阈值当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长,当网络拥塞时乘法减小,
拥塞控制, 归根结底是TCP协议想尽可能快的把数据传输给对方, 但是又要避免给网络造成太大压力的折中方案。
延时应答
- 延迟一会,等待缓存区中数据被处理,那么剩余的缓存区就会大些,这就是延时应答。
解释:假设接收端缓存区大小为1M,一次接收到了500K的数据,现在缓存区中剩余大小为500。但如果我们延时一段时间,等待接受方处理了该缓存区中的数据,那么我们的剩余大小就为1M了(即:窗口大小)。
补充:1.等待的时间每个操作系统中设置的等待时间是不一样的。(200ms)
2.数量限制:每隔两个包就应答一次 。
3.时间限制:超过最大延时时间就应答一次(200ms)
捎带响应
- 在延时应答的基础上,我们发现,接受方和发送方都是“一发一收”,所以,服务器在发送数据的时候,我们把ACK搭顺风车的方式发送给对方了。
小结
可靠性:
校验和,序列号(按序到达),确认应答,超时重发,连接管理,流量控制,拥塞控制
提高性能:
滑动窗口,快速重传,延迟应答,捎带应答
其他:
定时器(超时重传定时器, 保活定时器, TIME_WAIT定时器等)
TCP/UDP对比
TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景;
UDP用于对高速传输和实时性要求较高的通信领域, 例如, 早期的QQ, 视频传输等. 另外UDP可以用于广播。
粘包问题
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据
UDP的时候, 要么收到完整的UDP报文, 要么不收,所以不存在粘包问题
粘包问题的解决
明确两个包之间的边界
对于定长的包, 保证每次都按固定大小读取即可; 例如上面的Request结构, 是固定大小的, 那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;
对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔
符不和正文冲突即可);