看完这篇,面试再也不怕遇到网络协议和Netty相关的问题了


网络协议

TCP三次握手

在这里插入图片描述

TCP是面向连接的通信协议,面向连接是指在数据传输开始之前需要先建立连接,而TCP建立连接是通过三次握手进行的。在网络编程中,三次握手过程是由客户端执行connect连接来触发的,上图三次握手过程:

  1. 第一次握手:客户端发起连接请求报文,首先将标志位 SYN 置为 1,同时设置随机初始化序号seq=J,接着把当前 SYN 报文发送给服务端器(该报文不携带应用层数据),表示向服务器端发起连接,之后客户端进行 SYN_SENT 状态,等待服务器端确认
  2. 第二次握手:服务器端收到客户端的 SYN 报文后,根据报文中标志位 SYN=1得知客户端请求建立连接。然后服务器端回复应答报文,首先将标志位 SYN 和 ACK 都置为 1,并设置确认应答号 ack=J+1,同时设置随机初始化序号seq= K。最后将该报文发送给客户端(该报文不携带应用层数据),之后服务器端进行SYN_RCVD 状态
  3. 第三次握手:客户端收到服务端确认报文后,先检查确认应答号ack 是否为 J+1 以及ACK是否为 1,如果正确则需要向服务器端回复一个应答报文,首先将报文的标志位 ACK 置为 1,并设置确认应答号 ack=K+1。最后把报文发送给服务器端(该报文可以携带应用层数据),之后客户端进行ESTABLISHED 状态。而服务器端收到客户端的应答报文后,也会进入ESTABLISHED 状态

从上面的过程可以看到只有第三次握手才可以携带应用层数据的,前两次握手是不能携带数据的

为什么 TCP 握手需要三次

避免历史连接

在TCP 的协议 RFC 793 中就提到了使用三次握手的首要原因 —— 为了阻止历史的重复连接初始化造成的混乱问题,防止使用 TCP 协议通信的双方建立了错误的连接

想象一下这个场景,如果通信双方的通信次数只有两次,那么发送方一旦发出建立连接的请求之后它就没有办法撤回这一次请求,如果在网络状况复杂或者较差的网络中,发送方连续发送多次建立连接的请求,如果 TCP 建立连接只能通信两次,那么接收方只能选择接受或者拒绝发送方发起的请求,它并不清楚这一次请求是不是由于网络拥堵而早早过期的连接

所以,TCP 选择使用三次握手来建立连接并在连接引入了 RST 这一控制消息,接收方当收到请求时会将发送方发来的 SEQ+1 发送回接收方,这时由发送方来判断当前连接是否是历史连接:

  1. 如果当前连接是历史连接,即 SEQ 过期或者超时,那么发送方就会直接发送 RST 报文控制消息中止这一次连接;
  2. 如果当前连接不是历史连接,那么发送方就会发送 ACK 控制消息,通信双方就会成功建立连接;

使用三次握手和 RST 控制消息将是否建立连接的最终控制权交给了发送方,因为只有发送方有足够的上下文来判断当前连接是否是错误的或者过期的,这也是 TCP 使用三次握手建立连接的最主要原因

保证可靠传输

为了实现可靠数据传输, TCP 协议的通信双方,都必须维护一个序列号,序列号是可靠传输的一个关键点,它的作用:

  1. 接收方可以去除重复的数据
  2. 接收方可以根据数据包的序列号按序接收
  3. 可以标识发送出去的数据包中,哪些是已经被对方收到的

举例说明,当发送方在发送数据包(假设大小为 10 byte)时, 同时送上一个序号( 假设 为 500),那么接收方收到这个数据包以后, 就可以回复一个确认号(510 = 500 + 10) 告 诉发送方 “我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 511 开始” 。因此三次握手的过程即是通信双方相互告知序列号起始值,并确认对方已经收到了序列号起始值的必经步骤。 如果只是两次握手,至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认

TCP四次挥手

在这里插入图片描述

由于 TCP 连接是全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当主动方完成数据发送任务后,发送一个 FIN 给被动方来终止这一方向的连接,被动方收到一个 FIN 只是意味着不会再收到主动方数据了,但是被动方依然可以给主动方发送数据,直到这被动方也发送了 FIN 给主动方。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图四次挥手流程:

  1. 客户端发起连接释放报文,首先将标志位 FIN 置为 1,表示用来关闭客户端到服务器端的数据传输,之后客户端进入 FIN-WAIT-1 状态
  2. 服务器端收到连接释放报文后,就会向客户端发出 ACK 确认报文,此时服务器端就会进入CLOSE-WAIT状态,表示半关闭状态,即客户端已经没有数据要发送了,但是服务器端若发送数据,客户端依然要接受,此时相应的客户端收到服务器端的确认请求后,此时,客户端就进入FIN-WAIT-2状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)
  3. 等待服务器端将最后的数据发送完毕后,就会向客户端发送 FIN ACK 报文,此时会关闭服务器端到客户端的数据传输,服务器端进入last-ack
  4. 客户端收到服务器端的 FIN 报文后,会进入TIME-WAIT状态,接着发送确认报文 ACK。之后,服务器端在接收到 ACK 确认报文后,就会进入CLOSED状态,完成四次挥手。而客户端等待2MSL一段时间后也会进入CLOSED状态(linux设置msl为30秒)

为什么TCP的挥手需要四次

TCP 是全双工的连接,必须两端同时关闭连接,连接才算真正关闭。 在关闭连接时,客户端向服务器端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据,服务器端收到客户端的 FIN 报文时,会先回复一个 ACK 确认报文,而服务器端可能还有数据需要发送,等服务器将最后的数据发送完毕后,才发送 FIN 报文给客户端,客户端再回复 ACK报文,此时,两端都关闭,TCP连接正常关闭

为什么TIME-WAIT等待的时间是 2MSL(最大报文段生存时间)

防止收到旧连接的数据包

在 Linux 系统上,一个 TCP 端口不能被同时打开多次,当一个 TCP 连接处于 TIME_WAIT 状态时,我们无法使用该连接的端口来建立一个新连接。反过来思考,如果不存在 TIME_WAIT 状态,则应用程序能立即建立一个和刚关闭的连接相似的连接(这里的相似,是指他们具 有相同的 IP 地址和端口号)。这个新的的连接被称为原来连接的化身。新的连接可能收到属于原来连接携带应用程序数据的 TCP 报文段(迟到的报文段),这显然是不该发生的

可靠的终止TCP连接

客户端收到服务器的连接释放的 FIN 报文后, 必须发出确认。但是因为网络是不可靠的,这个 ACK 确认报文可能丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。如果ACK 确认报文丢失,服务器端没有收到ACK,将不断重复发送FIN报文。所以客户端不能立即关闭,它必须确认服务器端接收到了该ACK。客户端会在发送出ACK之后进入到TIME_WAIT状态。并会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么客户端会重发ACK并再次等待2MSL

TIME-WAIT过多有什么危害?

过多的 TIME-WAIT 状态主要的危害有两种:

  1. 内存资源占用
  2. 对端口资源的占用,一个TCP连接至少消耗一个本地端口

如果服务端 TIME-WAIT状态过多,占满了所有端口资源,则会导致无法创建新连接

建立连接后,客户端故障了怎么办

TCP有一个保活机制,原理是定义一个时间段,在这个时间段,如果没有任务连接相关的活动,TCP保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,如果未收到响应会继续发送,如果尝试发送次数超时保活探测数仍未收到响应则中断连接

在Linux内核可以有对应的参数可以设置保活时间、保活时间间隔、保活探测的次数,这些变量分别对应net.ipv4.tcp_keepalive_time、net.ipv4.tcp_keepalive_intvl、net.ipv4.tcp_keepalive_probes,默认设置是7200秒、75秒和9次探测。也就是说在Linux系统中,最少需要经过 2小时 11分 15秒才可以发现一次无效连接

DDOS 攻击

DDOS 攻击利用合理的服务请求占用过多的服务资源,使正常用户的请求无法得到相应。 常见的 DDOS 攻击有计算机网络带宽攻击连通性攻击

带宽攻击指以极大的通信量冲击网络,使得所有可用网络资源都被消耗殆尽,最后导致合法的用户请求无法通过

连通性攻击指用大量的连接请求冲击计算机,使得所有可用的操作系统资源都被消耗殆 尽,最终计算机无法再处理合法用户的请求

SYN 洪水攻击

SYN 洪水攻击属于 DDOS 攻击的一种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。 客户端在短时间内伪造大量不存在的 IP 地址,向服务器不断地发送 SYN 报文,服务器回复 ACK 确认报文,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,因此就会造成服务器等待连接队列被占满,使服务器无法处理正常用户的连接请求了

HTTP1.0 和 HTTP1.1 的区别

HTTP1.0 最早在网页中使用是在 1996 年,那个时候只是使用一些较为简单的网页上和网络请求上,而 HTTP1.1 则在 1999 年才开始广泛应用于现在的各大浏览器网络请求中,同时 HTTP1.1 也是当前使用最为广泛的 HTTP 协议。 主要区别主要体现在:

  1. 缓存处理,在 HTTP1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略
  2. 带宽优化及网络连接的使用,HTTP1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能, HTTP1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206 (Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接
  3. 错误通知的管理,在 HTTP1.1 中新增了 24 个错误状态响应码,如 409(Conflict)表 示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除
  4. Host 头处理,在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个 IP 地址。 HTTP1.1 的请求消息和响应消息都应支持 Host 头域,且请求消息中如果没有 Host 头域会报告一个错误(400 Bad Request)
  5. 长连接,HTTP 1.1 支持长连接(PersistentConnection)和请求的流水线(Pipelining) 处理,在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟,在 HTTP1.1 中默认开启 Connection: keep-alive,一定程度上弥补了 HTTP1.0 每次请求都要创建连接的缺点

HTTP2.0 和 HTTP1.X 相比的新特性

  1. 新的二进制格式(Binary Format),HTTP1.x 的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认 0 和 1 的组合。基于这种考虑 HTTP2.0 的协议解析决定采用二进制格式,实现方便且健壮
  2. 多路复用(MultiPlexing),即连接共享,即每一个 request 都是是用作连接共享机制的。 一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面
  3. header 压缩,如上文中所言,对前面提到过 HTTP1.x 的 header 带有大量信息,而且每次都要重复发送,HTTP2.0 使用 encoder 来减少需要传输的 header 大小,通讯双方各自 cache 一份 header fields 表,既避免了
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值