• 关于网络连接的一些易忘点-HTTP/TCP/UDP


    关于网络连接的一些易忘点-HTTP/TCP/UDP

    TCP和UDP

    TCP-传输控制协议(Transmission Control Protocol)

    • TCP提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。
    • TCP不提供广播或多播服务。由于TCP要提供可靠的,面向连接的传输服务(TCP的可靠体在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、流量控制、拥塞控制机制,在数据传完后,还会有四次挥手断开连接用来节约系统资源),这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。
    • TCP一般用于文件传输、发送和接收邮件、远程登录等场景

    UDP-用户数据报协议(User Datagram Protocol)

    • UDP在传送数据之前不需要先建立连接,远程主机在收到UDP报文后,不需要给出任何确认。
    • 虽然UDP不提供可靠交付,但在某些情况下UDP确是一种最有效的工作方式(一般用户即使通信),比如:QQ语音、QQ视频、直播等等

    TCP三次握手

    三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的

    img

    概览

    1. 第一次握手-客户端发送SYN报文给服务器,服务器接收该报文。

      客户端向服务端发送一个 SYN 报文(SYN = 1),并指明客户端的初始化序列号 ISN(x),即图中的 seq = x,表示本报文段所发送的数据的第一个字节的序号。此时客户端处于 SYN_Send 状态。

      客户端什么都不能确认;服务器确认了:客户端发送正常,自己接收正常。

    2. 第二次握手-服务器响应SYN报文给客户端,客户端接收该报文。

      服务器收到客户端的 SYN 报文之后,会发送 SYN 报文作为应答(SYN = 1),并且指定自己的初始化序列号 ISN(y),即图中的 seq = y。同时会把客户端的 ISN + 1 作为确认号 ack 的值,表示已经收到了客户端发来的的 SYN 报文,希望收到的下一个数据的第一个字节的序号是 x + 1,此时服务器处于 SYN_REVD 的状态。

      客户端确认了:自己发送正常、接收正常,对方发送正常、接收正常;服务器确认了:对方发送正常,自己接收正常。

    3. 第三次握手-客户端发送ACK报文给服务器。

      客户端收到服务器端响应的 SYN 报文之后,会发送一个 ACK 报文,也是一样把服务器的 ISN + 1 作为 ack 的值,表示已经收到了服务端发来的的 SYN 报文,希望收到的下一个数据的第一个字节的序号是 y + 1,并指明此时客户端的序列号 seq = x + 1(初始为 seq = x,所以第二个报文段要 +1),此时客户端处于 Establised 状态。服务器收到 ACK 报文之后,也处于 Establised 状态,至此,双方建立起了 TCP 连接。

      客户端确认了:自己发送正常、接收正常,对方发送正常、接收正常;服务器确认了:自己发送、接收正常,对方发送、接收正常。

    ISN (Initial Sequence Number) 是固定的吗?

    三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据

    当一端为建立连接而发送它的 SYN 时,它会为连接选择一个初始序号。ISN 随时间而变化,因此每个连接都将具有不同的 ISN。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的

    三次握手过程中可以携带数据吗?

    第三次握手的时候,是可以携带数据的。第一次、第二次握手绝对不可以携带数据。

    原因:假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,然后疯狂重复发 SYN 报文的话(因为攻击者根本就不用管服务器的接收、发送能力是否正常,它就是要攻击你),这会让服务器花费很多时间、内存空间来接收这些报文。

    半连接队列与全连接队列

    • 半连接队列:服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把这种状态下的请求连接放在一个队列里,我们把这种队列称之为半连接队列
    • 全连接:完成三次握手后建立起的连接就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

    SYN 洪泛攻击

    SYN 攻击就是 Client 在短时间内伪造大量不存在的 IP 地址,并向 Server 不断地发送 SYN 包,Server 则回复确认包,并等待 Client 确认,由于源地址不存在,因此 Server 需要不断重发直至超时,这些伪造的 SYN 包将长时间占用半连接队列,导致正常的 SYN 请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

    如果第三次握手丢失了,客户端服与务端会如何处理?

    服务器发送完 SYN-ACK 包,如果未收到客户端响应的确认包,也即第三次握手丢失。那么服务器就会进行首次重传,若等待一段时间仍未收到客户确认包,就进行第二次重传。如果重传次数超过系统规定的最大重传次数,则系统将该连接信息从半连接队列中删除。

    注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…

    TCP四次挥手

    img

    概览

    1. 第一次挥手:客户端发送一个 FIN 报文(请求连接终止:FIN = 1),报文中会指定一个序列号 seq = u。并停止再发送数据,主动关闭 TCP 连接。此时客户端处于 FIN_WAIT1 状态,等待服务端的确认。

      FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;

    2. 第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。

      CLOSE-WAIT - 等待从本地用户发来的连接中断请求;

      此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待 2)状态,等待服务端发出的连接释放报文段。

      FIN-WAIT-2 - 从远程TCP等待连接中断请求;

    3. 第三次挥手:如果服务端也想断开连接了(没有要向客户端发出的数据),和客户端的第一次挥手一样,发送 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态,等待客户端的确认。

      LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;

    4. 第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答(ack = w+1),且把服务端的序列值 +1 作为自己 ACK 报文的序号值(seq=u+1),此时客户端处于 TIME_WAIT(时间等待)状态

      TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束后才可继续使用。

      TIME-WAIT - 等待足够的时间以确保远程TCP接收到连接中断请求的确认;

      注意:这个时候由服务端到客户端的 TCP 连接并未释放掉,需要经过时间等待计时器设置的时间 2MSL(一个报文的来回时间) 后才会进入 CLOSED状态(这样做的目的是确保服务端收到自己的 ACK 报文。如果服务端在规定时间内没有收到客户端发来的 ACK 报文的话,服务端会重新发送 FIN 报文给客户端,客户端再次收到 FIN 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文给服务端)。服务端收到 ACK 报文之后,就关闭连接了,处于 CLOSED 状态。

    MSL-Maximum Segment Lifetime

    RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

    其他概念

    挥手为什么不直接关闭,而是进入TIME_WAIT等待状态?

    1.保证客户端发送的ACK报文段能够到达服务器,从而保证tcp连接能够进行可靠的关闭。

    这个很好理解,如果客户端发动ACK后就立刻关闭,那么如果ACK丢失的话,服务端就会一直处于等待关闭确认的状态,超时后再发送关闭请求时,此时的客户端已经关闭,那么服务端就无法进行正常的关闭。

    2.保证此次连接的数据段消失,防止失效的数据段。

    客户端在发送ACK后,再等待2MSL时间,可以使本次连接所产生的数据段从网络中消失,从而保证关闭连接后不会有还在网络中滞留的数据段去骚扰服务端;

    再有一点就是,如果客户端重新发送请求,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接(拥有相同五元组的路径)之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。

    五元组

    源IP,源端口号,目的IP,目的端口号,协议号

    • 源IP:发送数据的主机
    • 目的IP:接收数据的主机
    • 源端口:标识发送数据的进程
    • 目的端口:标识接收数据的进程
    • 协议号:进程要封装、解析的数据报的数据格式

    http头部信息Connection:keep-live

    keep-alive 是客户端和服务端的一个约定,如果开启 keep-alive,则服务端在返回 response 后不关闭 TCP 连接;同样的,在接收完响应报文后,客户端也不关闭连接,发送下一个 HTTP 请求时会重用该连接。

    keep-alive 技术创建的目的,就是能在多次 HTTP 之间重用同一个 TCP 连接,从而减少创建/关闭多个 TCP 连接的开销(包括响应时间、CPU 资源、减少拥堵等)。

    然而天下没有免费的午餐,如果客户端在接收完所有的信息之后还没有关闭连接,则服务端相应的资源还在被占用(尽管已经没用了)。例如 Tomcat 的 BIO 实现中,未关闭的连接会占用对应的处理线程,如果一个长连接实际上已经处理完毕,但关闭的超时时间未到,则该线程会一直被占用(使用 NIO 的实现没有该问题)。

    显然,如果客户端和服务端的确需要进行多次通信,则开启 keep-alive 是更好的选择,例如在微服务架构中,通常微服务的使用方和提供方会长期有交流,此时最好开启 keep-alive。

    在一些 TPS/QPS 很高的 REST 服务中,如果使用的是短连接(即没有开启keep-alive),则很可能发生客户端端口被占满的情形。这是由于短时间内会创建大量TCP 连接,而在 TCP 四次挥手结束后,客户端的端口会处于 TIME_WAIT一段时间(2*MSL),这期间端口不会被释放,从而导致端口被占满。这种情况下最好使用长连接。

    客户端如何开启keep-alive?

    • 对于浏览器而言,几乎你现在用的浏览器(包括 IE6)都默认使用 keep-alive 了。
    • Java8 中的 HttpURLConnection 默认开启长连接,但是默认连接池中只保留 5 个长连接1,如果同时超过 5 个线程在使用,则会创建新的连接,结束后多于 5 个的部分会被客户端主动关闭。
    • Apache HttpClient 默认为每个地址保留 2 个长连接,连接池中最多共保留 20 个连接2。
    • Python requests 如果使用 session 则会默认开启长连接。

    OSI-网络7层模型

    模型是从上往下的,越底层越接近硬件,越往上越接近软件,这七层模型分别是应用层表示层会话层传输层网络层数据链路层物理层

    • 应用层:各种应用软件,包括 Web 应用。
    • 表示层:数据格式标识,基本压缩加密功能。
    • 会话层:控制应用程序之间会话能力;如不同软件数据分发给不同软件。
    • 传输层:端到端传输数据的基本功能;如 TCP、UDP。
    • 网络层:定义IP编址,定义路由功能;如不同设备的数据转发。
    • 数据链路层:定义数据的基本格式,如何传输,如何标识;如网卡MAC地址。
    • 物理层:底层数据传输,如网线;网卡标准。

    TCP/IP4层模型

    TCP/IP 模型将 OSI 模型由七层简化为四层,传输层和网络层被完整保留,因此网络中最核心的技术就是传输层和网络层技术。

    • 应用层:应用层、表示层、会话层
    • 传输层:传输层
    • 互联网层:网络层
    • 网络访问层:数据链路层、物理层
  • 相关阅读:
    坚持自学软件测试,半年的辛苦没有白费,不过才拿到10k的offer
    windows server 2012 服务器打开系统远程功能
    【Koa】【MongoDB】koa框架连接MongoDB
    selenium 元素定位方法
    C++多态
    第46届ICPC东亚洲区域赛(昆明)补题题解 (B)
    java计算机毕业设计ssm贫困区教育资源捐赠平台element vue前后端分离
    使用图像处理跟踪瞳孔(Matlab代码实现)
    Nginx RPM打包
    每日一题,二叉树中增加一行
  • 原文地址:https://blog.csdn.net/qq_37279783/article/details/126389839