tcp/ip——1

6. 网络编程

参考
https://mp.weixin.qq.com/s/SZ8XcOzZCVJG_P1_O4OtWQ

6.1 TCP和UDP的特点与区别

  1. TCP
    是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,吧字节流组织成大小不等的数据块),每一条TCP连接只能是点对点的(一对一)

  2. UDP
    是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加UDP首部),支持一对一、一对多、多对一和多对多的交互通信

6.2 UDP和TCP首部格式

  1. UDP
    UDP首部字段只有8个字节,包括源端口、目标端口、长度、校验和。12个字节的伪首部是为了计算机检验和临时添加的
    avatar

  2. TCP
    avatar

序号:用于对字节流进行编号 seq
确认号ACK: 期望收到的下一个报文段的序号
数据偏移:指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度
控制位:8位从左到右分别是CWR\ECE\URG\ACK\PSH\RST\SYN\FIN
ACK:设置为1,确认应答的字段有效。TCP规定最初建立连接的时候出SYN包之外这个必须为1
SYN:用于建立连接,设置为1,表示希望建立连接。
FIN:设为1,表示今后不在有数据发送,希望断开连接。 当通信结束希望断开连接时,通信双方的主机之间就可以相互交换FIN位置为1的TCP段
note:每个主机又对对方的FIN包进行确认应答之后可以断开连接。不过主机收到FIN设置为1的TCP段之后不必马上恢复FIN包,而是可以等到缓冲区中所有的数据都因为已成功发送而被自动删除之后再发FIN包

窗口:窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的

6.3 TCP的三次握手

avatar

假设 A 为客户端,B 为服务器端。

首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。



A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。

B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。

A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。

B 收到 A 的确认后,连接建立。

为什么是三次

  1. 第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接

  2. 第二种理解。让客户机和服务器都知道自己的数据发送和接收能力是没问题的

6.4 TCP的四次挥手

avatar
客户端发送一个 FIN 段,并包含一个希望接收者看到的自己当前的序列号 K. 同时还包含一个 ACK 表示确认对方最近一次发过来的数据。

服务端将 K 值加 1 作为 ACK 序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作。

服务端发起自己的 FIN 段,ACK=K+1, Seq=L。

客户端确认。进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。ACK=L+1。

  1. 为什么建立连接时三次握手,关闭连接却是四次挥手
    一: TCP连接时双向传输的对等模式,就是说双方都可以同时向对象发送或接收数据。当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。

二:这时对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,也就是说,服务端收到客户端的 FIN 标志,知道客户端想要断开这次连接了,但是,我服务端,我还想发数据呢?我等到发送完了所有的数据后,会发送一个 FIN 段来关闭此方向上的连接。接收方发送 ACK确认关闭连接

注意,接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的,我只是一个“搬运工”,我无法了解“上层的意志”。

三:客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

四:4、因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发。

  1. TIME-WAIT
    客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
    确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。

    等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

6.5 TCP短连接和长连接的区别

  1. 短连接
    client向server发送消息,server回应client,然后一次读写就完成了,这时候双方任何一个都可以发起close操作,不过一般都是client先发起close操作。短连接一般只会在client/server间传递一次读写操作

短连接的优点:管理起来比较简单,建立存在的连接都是有用的连接,不需要额外的控制手段

  1. 长连接
    Client 与 Server 完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。

在长连接的应用场景下,Client 端一般不会主动关闭它们之间的连接,Client 与 Server 之间的连接如果一直不关闭的话,随着客户端连接越来越多,Server 压力也越来越大,这时候 Server 端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致 Server 端服务受损;如果条件再允许可以以客户端为颗粒度,限制每个客户端的最大长连接数,从而避免某个客户端连累后端的服务。

长连接和短连接的产生在于 Client 和 Server 采取的关闭策略,具体的应用场景采用具体的策略。

6.6 TCP拆包、粘包及解决办法

  1. 为什么常说TCP有粘包和拆包的问题而不说UDP
    UDP是基于报文发送,UDP首部采用了16bit来表示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开来,从而避免粘包和拆包的问题

而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP并没有把这些数据块区分边界,仅仅是一连串没有结构的字节流;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能

  1. 什么事粘包、拆包
    假设 Client 向 Server 连续发送了两个数据包,用 packet1 和 packet2 来表示,那么服务端收到的数据可以分为三种情况,现列举如下:
    第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象。
    avatar

第二种情况,接收端只收到一个数据包,但是这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。
avatar

第三种情况,这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。
avatar

  1. 为什么会发生粘包或者拆包
    要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。

待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。

要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。

接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

  1. 粘包、拆包解决方法
    由于 TCP 本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:

    消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

    设置消息边界:服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。

    将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。

    更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。

6.7 TCP的可靠传输

TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文段在超时时间内没有收到确认,那么就重传这个报文段。

6.8 TCP 滑动窗口

窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。

6.9 TCP流量控制

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。

6.10 TCP的拥塞控制

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
avatar

TCP 主要通过四个算法来进行拥塞控制:
慢开始、拥塞避免、快重传、快恢复。

cwnd ssthresh

6.11 提供网络利用率

  1. Nagle 算法
    发送端即使还有应该发送的数据,但如果这部分数据很少的话,则进行延迟发送的一种处理机制。具体来说,就是仅在下列任意一种条件下才能发送数据。如果两个条件都不满足,那么暂时等待一段时间以后再进行数据发送。

已发送的数据都已经收到确认应答。

可以发送最大段长度的数据时。

  1. 延迟确认应答
    接收方收到数据之后可以并不立即返回确认应答,而是延迟一段时间的机制。

在没有收到 2*最大段长度的数据为止不做确认应答。
其他情况下,最大延迟 0.5秒 发送确认应答。

TCP 文件传输中,大多数是每两个数据段返回一次确认应答。

  1. 捎带应答

在一个 TCP 包中既发送数据又发送确认应答的一种机制,由此,网络利用率会提高,计算机的负荷也会减轻,但是这种应答必须等到应用处理完数据并将作为回执的数据返回为止。

posted @ 2021-04-18 17:59  codeDJH  阅读(140)  评论(0编辑  收藏  举报