努力经营当下,直至未来明朗!
前言
一个人最大的痛苦来源于对自己无能的愤怒
Hi,这里还是不想秃头的宝贝儿!要努力不秃头啊!
本文主要介绍的是TCP提高效率的机制:延迟应答、捎带应答,以及TCP面向字节流的特性以及TCP的异常处理。
【回顾TCP】
① 确认应答:保证可靠传输的最核心机制
② 超时重传
③ 连接管理:三次握手(投石问路、发送能力和接收能力、协商参数)、四次挥手
④ 滑动窗口
⑤ 流量控制(通过接收方的处理能力/内核剩余接收缓冲区 来对发送方作出限制)
⑥ 拥塞控制(中间节点)
TCP相关机制
7. 延迟应答
【延迟应答】:提高传输效率的机制
- 延迟应答 是基于流量控制来引入的提高效率的机制
- 延迟应答:返回ACK的时间稍微晚一点,不是立即返回,此时应用程序就会有时间来消费内核接收缓冲区中的数据,使得接下来ACK返回的窗口略大于立即返回的窗口。
- 实际TCP的延时时间不一定非用时间来衡量,也可能是传输轮次来衡量。
8. 捎带应答
- 捎带应答是基于延迟应答的基础上引入的
- 网络通信中,典型的通信模型是一发一收。
- TCP中,只要把数据传输过去,对方收到后就会立即由内核返回一个ACK确认报文;而响应数据则是由应用程序负责传输的。所以,返回ACK和响应这两个操作是不同的时机传输的,就不能够把两次传输合并起来;但是延迟应答就会让ACK延迟返回,会稍微等一会儿,而在等待之后业务如果刚好也要返回响应,此时就可以把ACK与响应两个报文合二为一了(是由内核处理的,应用程序处理的响应也要经过内核,即:应用程序是调用socket的write方法把数据交给内核,内核进行封装,然后发送)。
- 补充:SYN-同步报文段; FIN-结束报文段; ACK-确认报文段
TCP补充
【面向字节流】
- 面向字节流中存在一个典型问题:“粘包问题”
- TCP或者其他面向字节流的传输方式都是有一个接收缓冲区的。由于是面向字节流的,所以接收方无法确定从哪开始从哪结束是一个完整的数据报。
- 要想解决粘包问题就在应用层协议这里进行区分:只要在定义应用层数据协议的时候,明确包和包之间的“边界”就可以了。
- 典型的办法有两种:
① 通过分隔符:比如约定使用;作为包的结束标记
② 通过指定包的长度:比如在数据报的开头位置声明长度 - 缓冲区的作用就是为了提高效率,减少访问I/O的开销
- UDP发送的时候也是有缓冲区的,但是不能够向TCP那样进行手动刷新(所以之前其实一直说的是UDP没有发送缓冲区,只有接收缓冲区);接收的时候是有缓冲区的。
- 具体代码中如何确定分隔符?(简单了解就行,没时间直接跳过)
在自定义应用层协议中有几个典型的实现:
①XML:分隔符就相当于结束标签
②JSON:分隔符就相当于}
③Protobuffer:里面通过申明长度的方式来确定边界
④HTTP:分隔符和长度两个都会用到
【TCP中的异常处理】
- TCP中的连接如果出现异常,怎么办?
1)程序崩溃
① 相当于进程的异常退出。而程序退出(正常or异常)之后操作系统就会回收进程的资源,包括释放文件描述符表,这样的释放操作就相当于调用了对应socket的close;执行close就会触发FIN报文,进一步开始四次挥手。
② 所以该情况与普通的四次挥手没啥区别。
2)正常关机(通过开始菜单这种方式来关闭主机)
关机的时候系统会先强制结束所有的用户进程,和上述的进程崩溃类似,系统内核会进行文件描述符表的释放操作,从而进一步进行四次挥手。
3)断电关机(主机掉电)
非常突然,猝不及防。
① 掉电的是接收方,发送方并不知道对面已经挂了,会继续发送数据。
但是此时发送的数据就没有ACK返回,发送方就会触发超时重传;重传了几次之后仍然没有应答,此时就会尝试重置连接(通过复位报文段),但是也会失败;此时就会直接放弃连接。
【复位报文段其实就是TCP报头中特殊标志位中的RST,为1就是有效的】
(补充:特殊标志位中:PSH:向对方所要数据,希望对方给个回应; URG:跟紧急指针相关)
② 掉电的是发送方,此时接收方就只能等着。
但是接收方也不是干等,等了一段时间之后就会发送一个“心跳包”,心跳包是周期性触发的,只是一个简单的不携带任何业务数据的包,存在的意义就是确认一下对方是否还在。
如果对方不返回心跳包,说明此时对方已经挂了。
4)网线断开
情况同主机掉电类似,只不过通信双方的主机都正常,这两端各自按照上述两种情况分别进行。
另(含面试题)
-
【TCP和UDP之间各自的应用场景对比】:
① TCP使用在有可靠性要求的场景中,使用TCP是非常广泛的。
② UDP用在对于可靠性要求不高,但是对于传输效率要求比较高的场景中。如机房内部的内网传输:【不容易丢包:带宽比较充裕,且网络结构相对简单】+【传输效率要求也比较高】 -
注:传输层并不是只有TCP和UDP两个协议的,还有其他协议:
像平时玩的LOL等实时性要求较高的游戏,一般既需要保证可靠性又需要保证效率,所以此时就可以使用KCP(但是不详细介绍)
3.【常见面试题】——经典
如何使用UDP来实现可靠传输?
(主要考查的其实是TCP)
其实就是基于UDP在应用层来实现确认应答、超时重传、引入序列号、滑动窗口(会确认都收到才滑到下一个)等等。(自己补充完善)
TCP小结
- 为什么TCP这么复杂?因为要保证可靠性,同时又尽可能的提高性能。
1)可靠性:
校验和 、序列号(按序到达)、 确认应答、 超时重传、 连接管理(三次握手、四次挥手)、 流量控制、 拥塞控制。
2)提高性能:
滑动窗口 、快速重传 、延迟应答 、捎带应答
3)其他:
定时器(超时重传定时器,保活定时器,TIME_WAIT定时器等)
- 基于TCP应用层协议
HTTP、 HTTPS、 SSH 、Telnet 、FTP、 SMTP
当然,也包括你自己写TCP程序时自定义的应用层协议
THINK
- TCP提高传输效率:延迟应答、捎带应答
- 面向字节流的“粘包问题”:分隔符、包长度
- TCP异常处理:程序崩溃、正常关机、主机掉电、网线断开
4.== 面试题:如何使用UDP来实现可靠传输?==【确认应答、超时重传、滑动窗口、引入序列号等】(不能使用流量和拥塞控制,因为是UDP是直接进行all发送的)