计算机网络之传输层 2
(一)TCP短连接和长连接的区别
1、 短连接
- Client 向 Server 发送消息,Server 回应 Client,然后一次读写就完成了。
- 这时候双方任何一个都可以发起 close 操作,不过一般都是 Client 先发起 close 操作。
- 短连接一般只会在 Client/Server 间传递一次读写操作。
- 短连接的优点:管理起来比较简单,建立存在的连接都是有用的连接,不需要额外的控制手段。
2、 长连接
- Client 与 Server 完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
- 在长连接的应用场景下,Client 端一般不会主动关闭它们之间的连接,Client 与 Server 之间的连接如果一直不关闭的话,随着客户端连接越来越多,Server 压力也越来越大,这时候 Server 端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致 Server 端服务受损;
- 如果条件再允许可以以客户端为颗粒度,限制每个客户端的最大长连接数,从而避免某个客户端连累后端的服务。
(二)TCP粘包、拆包及解决方法
- UDP 是基于报文发送的,UDP首部采用了 16bit 来指示 UDP 数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。
- TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 并没有把这些数据块区分边界,仅仅是一连串没有结构的字节流;另外从 TCP 的帧结构也可以看出,在 TCP 的首部没有表示数据长度的字段,基于上面两点,在使用 TCP 传输数据时,才有粘包或者拆包现象发生的可能。
1、 为什么会发生 TCP 粘包、拆包?
- 要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。
- 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。
- 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
2、 粘包、拆包解决办法
- 消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
- 设置消息边界:服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。
- 将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。
- 更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。
(三)TCP可靠传输
TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。
(四)TCP流量控制
- 流量控制是为了控制发送方发送速率,保证接收方来得及接收。
- 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
- 当发送窗口和接收窗口都等于1时,就是停止等待协议
- 实际上,为了避免此问题的产生,发送端主机会时不时的发送一个叫做窗口探测的数据段,此数据段仅包含一个字节来获取最新的窗口大小信息。
1、TCP滑动窗口RWND(TCP流量控制的一种方法)
定义
- 窗口是缓存的一部分,用来暂时存放字节流。
- 发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。
- 发送窗口内的字节都允许被发送,接收窗口内的字节都允许被接收。
- 如果发送窗口左部的字节已经发送并且收到了确认,那么就将发送窗口向右滑动一定距离,直到左部第一个字节不是已发送并且已确认的状态;
- 接收窗口的滑动类似,接收窗口左部字节已经发送确认并交付主机,就向右滑动接收窗口。
- 接收窗口只会对窗口内最后一个按序到达的字节进行确认,例如接收窗口已经收到的字节为 {31, 34, 35},其中 {31} 按序到达,而 {34, 35} 就不是,因此只对字节 31 进行确认。发送方得到一个字节的确认之后,就知道这个字节之前的所有字节都已经被接收。
后退N帧协议/滑动窗口
- 如果前一个帧在超时时间内未得到确认,就认为丢失或被破坏,需要重发出错帧及其后面的所有数据帧。
选择重传协议
- 需要设置缓存,并且接收端收到的数据包的顺序可能和发送的数据包顺序不一样
(五)TCP拥塞控制
1、TCP拥塞窗口CWND
定义
- 如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。
- 流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
拥塞控制的四个算法
(1)慢开始与拥塞避免
- 发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …
- 注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。
- 如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
(2)快重传与快恢复
- 在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
- 在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
- 在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。
- 慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
(六)提高网络利用率
1、Nagle 算法
- 发送端即使还有应该发送的数据,但如果这部分数据很少的话,则进行延迟发送的一种处理机制。
- 具体来说,就是仅在下列任意一种条件下才能发送数据,如果两个条件都不满足,那么暂时等待一段时间以后再进行数据发送:
- 已发送的数据都已经收到确认应答;
- 可以发送最大段长度的数据时。
2、延迟确认应答
- 接收方收到数据之后可以并不立即返回确认应答,而是延迟一段时间的机制:
- 在没有收到 2*最大段长度的数据为止不做确认应答;
- 其他情况下,最大延迟 0.5秒发送确认应答;
- TCP 文件传输中,大多数是每两个数据段返回一次确认应答。
3、捎带应答
- 在一个 TCP 包中既发送数据又发送确认应答的一种机制
- 由此,网络利用率会提高,计算机的负荷也会减轻,但是这种应答必须等到应用处理完数据并将作为回执的数据返回为止。
(七)数据报丢了怎么办
ARQ:自动重传请求(Automatic Repeat-reQuest)
- 通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。
- 如果发送方在发送后一段时间之内没有收到确认帧,它通常会重新发送。
- ARQ包括停止等待ARQ协议和连续ARQ协议,拥有错误检测(Error Detection)、正面确认(Positive Acknowledgment)、超时重传(Retransmission after Timeout)和 负面确认及重传(Negative Acknowledgment and Retransmission)等机制。
(1) 停止等待ARQ协议
- A发送分组M1,发送完就暂停发送,等待B的确认。信道利用率太低
(2) 连续ARQ协议
- 连续发送一组数据包,然后再等待这些数据包的ACK。
- 发送方采用流水线传输。流水线传输就是发送方可以连续发送多个分组,不必每发完一个分组就停下来等待对方确认。
- 连续ARQ协议通常是结合滑动窗口协议来使用的,发送方需要维持一个发送窗口,发送方每收到一个确认,就把发送窗口向前滑动一个分组的位置
(八)数据报被篡改?发生错误怎么检测?
1、发送方生成校验和
- 将待发送数据分成若干个16位的位串(如整数,浮点数等),每个位串看成一个二进制数;
- 将IP、UDP、TCP的PDU首部中的校验和字段置为0,该字段也参与校验和运算;
- 对这些16位的二进制数进行1的补码和运算,累加的结果再取反码即生成了校验码,将校验码放入校验和字段中。
2、 接收方校验校验和
- 接收方将接收的数据(包括校验和字段)按发送方同样的方法进行1的补码和运算,累加的结果再取反码;
- 校验,如果上步的结果为0,表示传输正确;否则传输出错。
(九)TCP中time_wait状态
1、 如何产生
- 当TCP连接发起一个主动关闭,并发出最后一个ACK时,会进入TIME_WAIT状态。必须在TIME_WAIT状态停留两倍MSL时间,在2MSL等待期间,定义这个连接的插口(客户端IP地址和端口号,服务器IP地址和端口号的四元组)将不能再被使用。
- MSL(Maximum Segment Lifetime)最大报文生存时间:每个TCP连接都必须有一个最大报文段生存时间MSL,在网络传输中超过这个时间的报文段将被丢弃。
- 一个MSL是确保主动关闭方最后的ACK能够到达对端。
- 一个MSL是确保被动关闭方重发的FIN能够被主动关闭方收到。
2、 产生的原因
- 实现TCP全双工连接的可靠释放
- 如果主动关闭方最终的ACk丢失,那么服务器将会重新发送那个FIN,允许主动关闭方重新发送ACK。client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。
- 如果主动关闭方不维护time_wait状态,那么主动关闭将会不得不响应一个RST报文段,而服务器将会把它解释为一个错误,导致TCP连接没有办法完成全双工的关闭,而进入半关闭状态。
- 允许旧的数据包在网络中因过期而消失
- 先关闭一条连接,然后以相同的四元组建立一条新连接。老的报文很有可能由于某些原因迟到了,那么新的TCP连接很有可能会将这个迟到的报文认为是新的连接的报文,而导致数据错乱。为了防止这种情况的发生TCP连接必须让TIME_WAIT状态持续2MSL,在此期间将不能基于这个插口建立新的化身,让它有足够的时间使迟到的报文段被丢弃。
3、 time_wait状态如何避免
- 服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。
- 在一个非常有用的场景就是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。