当前位置: 首页 > news >正文

【网络编程·传输层】UDP和TCP的报头


目录

一、端口号划分

二、部分指令

1、pidof(用于查看进程id)

2、netstat(查看网络状态)

三、UDP协议

1、UDP协议格式

2、UDP协议如何进行封装、解包、分用

2.1封装、解包

2.2分用

3、UDP协议的特点

3.1UDP协议的特点

3.2UDP协议的缓冲区

3.3UDP协议16位UDP长度

四、TCP协议(传输控制协议)

1、TCP协议格式

2、TCP协议的可靠性

2.1不可靠性的体现

2.2如何保证可靠性

3、TCP协议的报头

3.1封装、解包(4位首部长度)

3.2分用(16位源端口号、目的端口号)

3.3TCP协议的32位序号和确认序号(滑动窗口、超时重传去重有用到该字段)

3.4TCP协议的16位窗口大小(用于控制发送报文的速度)

3.5TCP协议的6个标志位(区分报文类型)

4、确认应答机制(ACK)

5、超时重传机制

6、连接管理机制

6.1三次握手(建立连接是客户端发起)

6.2四次挥手(断开连接是双方的事情)

7、流量控制

8、滑动窗口/快速重传机制

8.1滑动窗口的本质

8.2滑动窗口的作用

8.3关于滑动窗口的一些问答

9、拥塞控制

10、延迟应答

11、捎带应答

12、理解TCP的面向字节流和UDP的面向数据报

13、粘包问题

14、TCP建立连接异常的问题

五、UDP/TCP协议总结

1、TCP的可靠性和性能

2、UDP和TCP的协议的适用场景

3、关于listen的第二个参数


一、端口号划分

端口号是一个16位的无符号整型,取值范围为0-65535。

0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的。

如下是一些约定俗成的端口号:

ssh服务器, 使用22端口

ftp服务器, 使用21端口

telnet服务器, 使用23端口

http服务器, 使用80端口

https服务器, 使用443

1024 - 65535: 操作系统动态分配的端口号。 客户端程序的端口号, 就是由操作系统从这个范围分配的。 

二、部分指令

1、pidof(用于查看进程id)

pidof httpServer | xargs kill -9//xargs用于将标准输入转换为命令行参数

2、netstat(查看网络状态)

n 拒绝显示别名,能显示数字的全部转化成数字
l 仅列出有在 Listen (监听) 的服务状态
p 显示建立相关链接的程序名
t (tcp)仅显示tcp相关选项
u (udp)仅显示udp相关选项
a (all)显示所有选项,默认不显示LISTEN相关

三、UDP协议

1、UDP协议格式

如果校验和出错,该报文就会被丢弃。

UDP报头本质上是一个结构体对象或者包含位段的结构体。

struct udphdr {uint16_t uh_sport;  /* 源端口号 */uint16_t uh_dport;  /* 目的端口号 */uint16_t uh_ulen;   /* UDP数据报长度(包括头部+数据) */uint16_t uh_sum;    /* 数据校验和 */
};

2、UDP协议如何进行封装、解包、分用

2.1封装、解包

我们之前在自定义协议的时候,采用特殊字符进行区分报头和有效载荷。

UDP协议直接按照报头长度固定的方式,认为前8个字节是报头。

2.2分用

UDP的报头中包含16位的目的端口号,在对方应用层中存在了一个绑定了这个端口号的进程,上层绑定该端口号的进程就可以通过文件描述符的形式读到,交给应用层具体的协议进行处理。

3、UDP协议的特点

3.1UDP协议的特点

UDP传输的过程类似于寄信,把信寄出去就完事了,不会去管对方有没有收到。

无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;

不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方导致丢包, UDP协议也不会给应用层返回任何错误信息;

面向数据报: 不能够灵活的控制读写数据的次数和数量,sendto几次就recvfrom几次。应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并; 用UDP传输100个字节的数据: 如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节

UDP成功读取都将读取到一个报文,我们不用考虑报头的问题,只需要做好有效载荷的序列化与反序列化问题即可。

3.2UDP协议的缓冲区

不要考虑多个UDP报文粘连的问题,因为UDP没有真正意义上的发送缓冲区. 调用sendto会直接交给内核(应用层发一个,传输层送走一个), 由内核将数据传给网络层协议进行后续的传输动作;

UDP具有接收缓冲区。但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致; 如果缓冲区满了, 再到达的UDP数据就会被丢弃;所以UDP协议是一种全双工的协议。

3.3UDP协议16位UDP长度

UDP协议报头中有一个16位UDP长度的字段,就是说一个UDP报文最大可传输的长度为2^16即64KB(包含UDP首部8字节),如果需要传输大于64KB的数据,就需要应用层多次分包,并在接收端手动拼装。

四、TCP协议(传输控制协议)

1、TCP协议格式

其中报头就是一个结构体对象:

struct tcphdr 
{uint16_t th_sport;  /* 源端口号 */uint16_t th_dport;  /* 目的端口号 */uint32_t th_seq;    /* 序列号 */uint32_t th_ack;    /* 确认号 */uint8_t th_off;     /* 偏移量,指明TCP报文头的长度,单位是4个字节 */uint8_t th_flags;   /* 控制标志,如SYN、ACK、FIN等 */uint16_t th_win;    /* 接收窗口大小 */uint16_t th_sum;    /* 校验和 */uint16_t th_urp;    /* 紧急指针 */
};

2、TCP协议的可靠性

2.1不可靠性的体现

网络传输距离很长,路上会经过多个设备节点,所以在路上可能会存在丢包、乱序、校验错误、报文重复等问题。

2.2如何保证可靠性

一条报文只有收到了对方的应答,才能保证报文的可靠性。双方通信,一定存在最新的数据,例如图中“现在是12点”这条报文,暂未收到对方的应答,所以这条报文有没有被收到是不可靠的。

报文的应答既可以单独发送,也可以和要发送的数据可以合为一条报文进行发送,例如上图,后续服务器回复“我收到现在是12点这条消息了,那我们13点去玩吧!”这就是将应答和要传的数据塞到一条报文里。

无论是客户端给服务器发消息还是服务器给客户端发消息,每条消息都必须给应答。当然不用给纯应答报文做应答哈。

3、TCP协议的报头

3.1封装、解包(4位首部长度)

可以将TCP协议的前20个字节转换为一个结构化的数据,就可以提取出标准报头中的4位首部长度。TCP报文总长度=4位首部长度*4字节=【20字节(最低20字节),60字节】。可以根据首部字段计算得到的TCP报文总大小-标准报文大小,得到的就是剩余报头的大小,剔除所有报文信息,剩下的就是有效载荷。

3.2分用(16位源端口号、目的端口号)

TCP的报头中包含16位的目的端口号,服务器启动时绑定了端口号,就可以找到该TCP报文对应的应用层进程了。操作系统维护网络进程PCB和端口号的数据结构是哈希表。

3.3TCP协议的32位序号和确认序号(滑动窗口、超时重传去重有用到该字段)

客户端可能短时间内发送多个报文,注意这些报文到达服务器的顺序是不确定的。那么客户端收到服务器的应答之后,该如何区分该条应答对应我之前发送的哪条请求呢?这是因为TCP协议中存在32位序号和32位确认序号。

序列号(Sequence Number)是TCP协议中用于标识数据包的字段,它表示发送方发送的数据包的字节流中的第一个字节的序号。序列号的作用是确保数据包的顺序和完整性。在TCP协议中,每个数据包都有一个唯一的序列号。

确认号(ACK Number)是TCP协议中用于确认接收方已经成功接收到数据包的字段,它表示接收方期望下一个收到的数据包的序列号。在TCP协议中,接收方需要发送一个确认包(ACK包)来告诉发送方已经成功接收到数据包。确认包中的ACK Number字段就是接收方期望下一个收到的数据包的序列号。

搞两组序号的原因是TCP协议是全双工的,客户端、服务器均可能充当发送方或接收方,所以需要使用两组序号。

3.4TCP协议的16位窗口大小(用于控制发送报文的速度)

TCP协议在发送数据时,发送方发送过快会导致接收方来不及读取,报文将塞满对方的输入缓冲区,对方缓冲区都满了还发,新发的报文将会被直接丢弃。那么就需要控制发送报文的速度。

TCP协议中存在16位窗口大小,用于填写自己的输入缓冲区的大小。该报文传输至对方,对方就知道自己这边剩余输入缓冲区的空间还剩多少,就能控制发送数据的速度了。

16位窗口大小的存在实现了通信双方交换接收能力的作用,达到流量控制。

3.5TCP协议的6个标志位(区分报文类型)

服务器可能会面对多种不同类型的客户端,可能有发起连接的报文,可能有应答的报文等,为了区分不同类型的报文,TCP报头设置了多种01标志位。

  1. URG:置位了,紧急指针字段才有效
  2. ACK:确认报文段已收到
  3. PSH:催促接收方,让其上层尽快取走输入缓冲区数据(push),即便缓存区未满
  4. RST:复位,强制关闭一个异常连接
  5. SYN:请求建立一个连接
  6. FIN:断开一个连接

4、确认应答机制(ACK)

TCP将每个字节的数据都进行了编号。即为序列号。每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发。

5、超时重传机制

网络传输的一大不可靠性就是丢包问题,TCP协议的解决方式是超时重传。

如果主机A发送数据给B后,由于网络问题丢包了,B自然不会给A应答。如果主机A发现一段时间间隔没有收到确认应答,就会进行重发。

如果主机A发送给主机B后,主机B接收到了报文,但是返回的应答丢了,主机A在一段时间后也会重传。

这样接收方将会收到两份一样的报文,收到重复的数据,也体现了不可靠性,接收方需要进行根据32位序号进行去重。

重传时间:由于数据传输和当时的网络环境有关,所以重传时间不能设定为固定值,而是由操作系统动态的调整重传时间。

TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间。

Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍。

如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传。

如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增。

累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接。

6、连接管理机制

三次握手是创建TCP连接结构体的基础。TCP连接结构体是维护超时重传、按序到达、流量控制、连接状态等保证可靠性的数据结构。

TCP的面向连接间接的保证了通信的可靠性,同时UDP协议因为是无连接的,并不会维护超时重传、按序到达、流量控制等数据结构,所以UDP是不可靠的。 

  1. CLOSED: 初始状态,表示TCP连接未建立或已终止。
  2. LISTEN: 表示该TCP端口正在等待连接请求。
  3. SYN-SENT: 表示TCP连接请求已经发送给远程主机,等待响应确认。
  4. SYN-RECEIVED: 表示TCP连接请求已被服务器接受,并且已回复以确认连接请求。
  5. ESTABLISHED: 表示TCP连接已成功建立,可以开始进行数据传输。
  6. FIN-WAIT-1: 表示TCP连接已经关闭,但本地端点仍然可以发送数据,等待远程端点的确认。
  7. CLOSE-WAIT: 表示TCP连接已经收到对端的关闭请求,本地端口仍然可以发送数据,然后关闭连接。
  8. FIN-WAIT-2: 表示TCP连接已准备好关闭,但远程端点还有数据需要传输,等待远程端点的关闭请求。
  9. LAST-ACK: 表示TCP连接在本地端口和远程端口两端都已发出关闭请求并得到确认,发送最后的确认完成连接关闭。
  10. TIME-WAIT: 表示TCP连接已正常关闭,正在等待所有相关网络报文被清除,通常需要经过一个固定的时间间隔后方可进入CLOSED状态。

6.1三次握手(建立连接是客户端发起)

SYN_SENT是TCP/IP协议中的一种状态,它代表了一个已经发送了连接请求(SYN)的TCP客户端,并正在等待对方返回连接确认(ACK)的过程。在TCP三次握手连接过程中,当客户端发送SYN包后,客户端的TCP状态就会变成SYN_SENT。在这个状态下,TCP客户端将继续尝试向服务器发送SYN包,直到收到服务器返回的ACK包才能建立连接。

SYN_RECV,它是TCP/IP协议中的一种状态。在TCP连接建立的过程中,服务器端在收到客户端的SYN包后,会发送ACK和SYN包作为回复,表示已经成功接收到客户端的连接请求,并且向客户端发起连接确认请求。此时服务器的TCP状态就变成了SYN_RECV。在这个状态下,服务器会等待客户端的ACK包,以完成TCP三次握手连接的过程。如果在一段时间内没有收到客户端的ACK包也不用担心,服务器会认为自己的ACK+SYN包被丢失了,会发起超时重传。

客户端正在第三次握手发出ACK时就认为三次握手完成,服务器只有收到了客户端的这个ACK应答,才认为三次握手完成。客户端、服务器三次握手完成的时间是有差别的。三次握手不一定非得成功,尤其是客户端最后一个ACK的是否丢失客户端是不知道的,但是我们有超时重传等机制解决这个问题。

为什么一定要三次握手?

因为TCP在传输层,属于操作系统管理,维护TCP连接是有时间和空间成本的。

如果握手次数仅一次,客户端仅发送一次SYN即建立连接成功,那么某些恶意分子就可以使用客户端疯狂connect发起连接,服务器维护连接是有成本的,会导致服务器上的可用连接越来越少(SYN洪水)。

如果握手次数是两次。和握手一次的情况是一样的,客户端发送完SYN后,服务端返回SYN+ACK后,服务端即认为连接建立成功。同样会引发SYN洪水。

为什么要采用三次握手呢?首先TCP是全双工的通信协议,三次握手是验证全双工通信正常与否的最小代价。其次为了防止SYN洪水,三次握手的最后一次发起连接的是客户端,客户端最后一次发出ACK的时候,代表连接成功,客户端想在服务端建立连接就必须现在客户端建立连接。客户端想发动SYN洪水攻击其本身也会受到同等的消耗,三次握手可以有效规避单主机下的SYN攻击。(不过需要注意的是,防止SYN洪水攻击,并不是TCP协议来解决的,TCP协议的主要任务是网络通信!)

如果握手次数是四次,是不行的,最后一次服务端发送ACK应答后,就会在自己这里建立连接,只要客户端想办法不收到这个连接,就不会在客户端建立连接关系,存在SYN洪水攻击的风险。

如果握手次数是大于三次奇数次,握手三次已经能满足要求了,没必要增加握手次数浪费双方的时间。

6.2四次挥手(断开连接是双方的事情)

断开连接是双方的事情,需要征得双方同意。

四次挥手阶段,客户端和服务器都可以主动发起断开连接。

一方想断开连接的时候,另一方可能也想断开连接,可能会导致四次挥手变成三次挥手。

主动断开连接的一方,最终状态是TIME_WAIT,被动断开连接的一方,两次挥手完成会进入CLOSE_WAIT状态。如果被断开一方出现大量的CLOSE_WAIT状态,要么是服务器压力过大来不及执行close(服务端还有数据没有推送完),要么是你的close直接就是忘写了。

四次挥手完成,主动断开连接的一方会维持一段时间的TIME_WAIT。

维持多久:这个时间是两倍的MSL(MSL:一个TCP报文段在网络中的最长生存时间,超过这个时间,报文段将被丢弃。MSL的默认值为2分钟(CentOS7为1分钟)。)

为什么要维持一段时间:1、因为四次挥手的最后一次ACK应答,发起方无法确认对方是否收到,需要等待一段时间,如果被动方补发了第三次挥手的FIN报文,这时主动方就可以进行第四次挥手的ACK应答报文补发,尽可能保证四次挥手成功。2、双方在断开连接的时候,网络中还有滞留的报文,需要等待所有相关网络报文被清除。(否则服务器立刻重启, 可能会收到来自上一个进程的迟到的数据, 但是这种数据很可能是错误的);

若服务器先关闭,一段时间内重启服务器将不能再绑定上一次绑定的端口,必须等上一次服务器状态变为CLOSED后,那个端口才可以重新用于连接。对于访问量大的服务器,如果挂了,那么大量的端口在一段时间内无法再次被绑定,所以这是不合理的。使用setsockopt()允许创建端口号相同但IP地址不同的socket描述符。

GETSOCKOPT(2)         
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
int opt=1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

7、流量控制

上面章节说过,TCP报文中存在16位窗口大小,实际上, TCP首部40字节选项中还包含了一个窗口扩大因子M, 实际窗口大小是窗口字段的值左移 M 位。用于交换双方接收缓冲区的大小。在三次握手时,双方就在TCP报文中顺带的完成了接收缓冲区的大小的交换。

当接收端接收缓冲区已满,会有两种策略:1、当接收端上层拿走了数据,接收端会向发送方发送一个窗口更新通知;2、发送端会时不时的询问接收端的窗口大小。

8、滑动窗口/快速重传机制

8.1滑动窗口的本质

滑动窗口本质是发送缓冲区的一部分,发送缓冲区中已发送未应答的部分称为滑动窗口。

滑动窗口的移动本质是数组下标的移动。

8.2滑动窗口的作用

  1. 流量控制:TCP滑动窗口机制允许接收方控制发送方的发送速率,以确保接收方能够在处理能力范围内接收和处理数据。接收方通过调整滑动窗口的大小来告知发送方,它还能够根据接收方的处理能力动态地调整滑动窗口的大小。滑动窗口一定程度上提高了TCP对数据的传输效率。
  2. 拥塞控制:TCP滑动窗口机制能 够帮助控制网络中的拥塞情况。当网络发生拥塞时,接收方可以减小滑动窗口的大小以减缓数据的发送速率,从而避免对网络造成进一步的负载压力。通过动态调整滑动窗口的大小,TCP能够根据网络的拥塞程度自适应地控制数据的传输速率。
  3. 可靠性传输:TCP滑动窗口机制提供了可靠的数据传输。发送方只有在收到接收方确认的数据后才会发送下一个滑动窗口的数据,接收方同时也会对接收到的数据进行确认。如果发送方没有收到确认或者接收方收到失序的数据,发送方可以通过滑动窗口机制选择性重传这些数据,以确保数据的可靠传输。

8.3关于滑动窗口的一些问答

滑动窗口开始的大小是怎么设定的?未来如何变化:

滑动窗口大小指的是无需等待确认应答而可以直接发送数据的最大值。上图的窗口大小就是4000个字节(四个段)。滑动窗口的大小和对方的接收能力有关。 

滑动窗口一定是向右滑动吗?会向左滑动吗:

滑动窗口可能会向右滑,也可能不动(对方接收缓冲区满了,暂停滑动)。但绝不会向左滑,因为左边的数据都是已发送已应答的。

滑动窗口的大小会改变吗?如何改变:

滑动窗口根据对方的接收能力动态变化,可能增大,也可能减小。

滑动窗口中的数据收到应答的先后顺序并不相同,如果先ACK中间或者尾部的数据,滑动窗口应该怎么处理:

滑动窗口ACK乱序不影响,只要最左侧的ACK到了,滑动窗口就右移。

最怕的发生丢包问题:

1、如果是数据没丢,而是ACK丢了。这个不怕,因为TCP协议中有32位确认序号,例如1001-2000序号的ACK丢了,只要客户端收到2001-3000序号(比2000大就行)的ACK,就说明之前的报文都收到了,此时直接将窗口滑动至3001。

2、如果数据丢了(服务端没收到数据,当然ACK也是没有的),客户端后续收到三个相同序号的ACK包时,会触发快速重传机制

如果向后滑动,后方空间不足该怎么处理:

发送缓冲区被操作系统内核组织成了环形的结构。(和环形结构的生产者消费者模型类似)

9、拥塞控制

路上的车多了,难免会堵车。网络也一样,同时有多台主机进行TCP通信,也会造成网络拥塞。各个接收主机突然出现大量的丢包现象,如果此时贸然对大量丢失的报文进行超时重传,对网络状态的缓解无疑是雪上加霜。

当发生拥塞时,TCP会启用慢启动机制,所有主机先发送少量的数据用于探路(减少了同一时间发送的报文数量,大大缓解了网络压力),摸清网络的状况后再提升发送速率。如下图:

图上还有一个拥塞窗口(大小根据网络状态变化)的概念,体现网络的的存储能力。

慢启动机制:

1、发送开始的时候, 定义拥塞窗口大小为1;

2、每次收到一个ACK应答, 拥塞窗口加1; (翻倍,1变2,2变4,4变8。指数级增长,前期利用指数增长进行慢启动探路,探路若成功,说明网络OK,同时指数快速爆炸,迅速将通讯速度恢复到最大。拥塞窗口在增长后期翻倍增长已经没有意义了,因此后期不能使拥塞窗口单纯的加倍,需引入一个叫做慢启动的阈值。当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长)

3、实际发送的窗口大小=min(拥塞窗口,对端主机提供的TCP报头中的16位窗口大小);

对于第三点的解释:

发送端发送能力取决于以下三种情况:

1、发送端的滑动窗口大小;

2、对端主机提供的TCP报头中的16位窗口大小。(对端接收缓冲区)

3、当前网络的拥塞窗口

1、当TCP开始启动的时候, 慢启动阈值等于窗口最大值; (图中等于24)

2、在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1(图中阈值从24降为12)

10、延迟应答

发送端发了一个报文至对端的接收缓冲区中,对端接收到该报文后发现接收缓冲区还剩1M,如果立即进行应答,告诉发送端我的接收缓冲区还剩1M,那么发送端下一次将会按照1M的容量进行流量控制。如果对端采取延时应答,那么上层将有概率取走一些接收缓冲区中的报文,这样就可以应答一个更大的空间,同时可以减少应答次数(TCP中有32位确认序号,可以保证之前序号的报文已经收到了)。延迟应答可以增加网络吞吐量

当然并不是说每个包都延迟应答。

1、数量限制: 每隔N个包就应答一次;

2、时间限制: 超过最大延迟时间就应答一次;(一定小于超时重传时间)

具体的数量和超时时间, 依操作系统不同也有差异; 一般N取2, 超时时间取200ms;

11、捎带应答

一端给另一端发消息,另一端为了减少报文的传输,会把ACK标志位置1并且带上32位确认序号的同时,再加上有效载荷一并发送给对端。(携带有效载荷的应答,这也是TCP中比较常见的通信方式,能提高消息的传输效率)

12、理解TCP的面向字节流和UDP的面向数据报

应用层调用write的本质就是将数据拷贝到发送缓冲区,如果数据满将会被挂起;应用层调用read的本质就是将数据从接收缓冲区中读出,如果数据满将会被挂起。由于双方各有一个读/写缓冲区,所以TCP是一种全双工的通信协议。

对于TCP协议来说,它并不关心应用层给的数据中,多少长度为一个报文,在它眼里,应用层给的全部是一个个字节。由于缓冲区的存在,TCP协议的读和写并需要匹配,上层给多少或者想要多少以及如何将这些字节组合成一个个报文的,TCP根本不关心,想要组合成报文,应用层自己想办法例如应用层可以调用多次write写入总计写入100字节,对端可以调用一次read将100字节读出。(UDP是面向数据报,发一次必须读一次,每次收到的必定是一个报文,后续再对这个报文进行序列化和反序列化即可。对于这种独立的报文的传输称为面向数据报)

13、粘包问题

上面说了,TCP不管报文的合成,需要应用层自己解决粘包问题。

解决粘包问题的本质是明确报文和报文之间的边界。

如何明确边界:

1、定长读取策略:对于定长的包, 保证每次都按固定大小读取即可; 例如上面的Request结构, 是固定大小的, 那么就从缓冲区从头开始按sizeof(Request)依次读取即可;

2、包头约定包长策略对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置;

3、特殊字符分隔策略对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序员自己来定的, 只要保证分隔符不和正文冲突即可)

14、TCP建立连接异常的问题

1、TCP客户端和服务器某一方或者全部挂掉了

在挂掉之前,TCP客户端和服务器是存在连接的。一旦某一方挂掉了,操作系统会自动发起四次挥手,正常断开连接。(和手动调用close没有区别) 

2、机器重启

OS都寄了进程当也寄了。重启前操作系统会把进程先退出,所以这种情况和进程正常退出没有区别。

3、机器掉电或者网线被拔

被掉电的一端根本来不及给对端发消息就寄了,对端会定期发起询问,多次无应答后将会断开连接。(对于连接的管理机制,大都是应用层来管理的(HTTP、HTTPS等)应用层的某些协议, 也有一些这样的检测机制,例如HTTP长连接中, 也会定期检测对方的状态. 例如QQ在断线之后, 也会定期尝试重新发起TCP三次握手进行连接)

五、UDP/TCP协议总结

1、TCP的可靠性和性能

可靠性:

校验和、序列号(按序到达)、确认应答、超时重传、连接管理、流量控制、拥塞控制

提高性能:

滑动窗口、快速重传、延迟应答、捎带应答、流量控制、拥塞控制

2、UDP和TCP的协议的适用场景

UDP用于对高速传输和实时性要求较高的通信领域, 例如, 直播、早期的QQ, 视频传输等. 另外UDP可以用于广播

TCP用于可靠传输的情况, 应用于文件传输, 重要状态更新等场景;

用哪种协议最终还是得按公司领导说了算。

3、关于listen的第二个参数

int listen(int sockfd, int backlog);

TCP协议要为上层维护一个全连接队列,队列里面是已经完成三次握手的待连接对象,这个队列不能没有,它的存在就好比去外面吃饭,需要排队的场景,上一个顾客走了,在排队的用户马上可以接上来,大大提高TCP的速度,当然这个队列也不能太长,因为队伍太长你还愿意等吗,TCP也一样,队列太长没必要,因为维护这个队列是需要开销的。这个全连接队列受listen的第二个参数的影响。

listen的第二个参数设置为2,在第四次建立连接的时候(客户端36648),可以看到客户端认为自己建立连接成功了,但是在服务器端,连接建立的状态是SYN_RECV。(客户端发起建立连接的请求,服务器收到后处于SYN_RECV状态并向客户端发送SYN+ACK应答,使客户端建立成功连接,但是客户端发起第三次握手的时候会无视该客户端的ACK,说话以服务器并不会建立连接,仍处于SYN_RECV的状态称为半连接状态

tcp底层最多允许backlog+1个全连接,后续来的全部都是半连接。(半连接如果没有尽快完成握手,会被server自动关掉)

1. 半链接队列(用来保存处于SYN_SENT和SYN_RECV状态的请求)

2. 全连接队列(accpetd队列)(用来保存处于established状态,但是应用层没有调用accept取走的请求)

相关文章:

【网络编程·传输层】UDP和TCP的报头

目录 一、端口号划分 二、部分指令 1、pidof&#xff08;用于查看进程id&#xff09; 2、netstat&#xff08;查看网络状态&#xff09; 三、UDP协议 1、UDP协议格式 2、UDP协议如何进行封装、解包、分用 2.1封装、解包 2.2分用 3、UDP协议的特点 3.1UDP协议的特点 …...

C语言编程技巧 全局变量在多个c文件中公用的方法

在使用C语言编写程序时&#xff0c;经常会遇到这样的情况&#xff1a;我们希望在头文件中定义一个全局变量&#xff0c;并将其包含在两个不同的C文件中&#xff0c;以便这个全局变量可以在这两个文件中共享。举个例子&#xff0c;假设项目文件夹"project"下有三个文件…...

【HDFS】NN处理全量块汇报时reportDiff的一些细节

NN处理全量块汇报(FBR)时的一些细节怎么生成的toRemove怎么check 汇报上来的块是不是corrupt的?reportDiff方法里巧妙地引入delimiterBlock这个block的作用前置知识:【HDFS】Block、BlockInfo、BlockInfoContiguous、BlockInfoStriped的分析记录 上面的文章中介绍了关于Bl…...

JVM之类加载与字节码(一)

1.类文件结构 一个简单的HelloWorld.Java package cn.itcast.jvm.t5; // HelloWorld 示例 public class HelloWorld { public static void main(String[] args) { System.out.println("hello world"); } }编译为 HelloWorld.class 后的样子如下所示&#xff1a; […...

【数据结构OJ题】合并两个有序数组

原题链接&#xff1a;https://leetcode.cn/problems/merge-sorted-array/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 看到这道题&#xff0c;我们注意到nums1[ ]和nums2[ ]两个数组都是非递减的。所以我们很容易想到额外开一个数组tmp[ ]&#x…...

数据结构笔记--归并排序及其拓展题(小和问题、逆序对问题)

目录 1--归并排序 2--小和问题 3--逆序对问题 1--归并排序 归并排序的核心思想&#xff1a;将一个无序的序列归并排序为一个有序的系列&#xff1b;通过递归将无序的序列二分&#xff0c;从底层开始将二分的序列归并排序为有序序列&#xff1b; #include <iostream> #…...

flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能

flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能 在之前项目开发中&#xff0c;遇到更换样式&#xff0c;由于从服务器端获取的样式均为css属性值&#xff0c;需要将其转换成flutter类对应的属性值。这里只处理线性渐变linear-gradient 比如渐变 “linear-…...

python推理小游戏bagels

python推理小游戏bagels bagels是一个推理小游戏&#xff0c;你的朋友想到一个随机的、没有重复的3位数字&#xff0c;你尝试去猜测它是什么。每次猜测之后&#xff0c;朋友就会给出3中类型的线索&#xff1a; Bagels: 你猜测的3个数都不在神秘数字中&#xff1b;Pico&#x…...

DBSCAN聚类

一、概述 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种基于密度的聚类算法&#xff0c;簇集的划定完全由样本的聚集程度决定。聚集程度不足以构成簇落的那些样本视为噪声点&#xff0c;因此DBSCAN聚类的方式也可以用于异常点的检测。 二、算法…...

java+ssm美食推荐交流系统 7jsw7

随着社会的发展&#xff0c;美食推荐系统的管理形势越来越严峻。越来越多的用户利用互联网获得信息&#xff0c;但美食推荐信息鱼龙混杂&#xff0c;真假难以辨别。为了方便用户更好的获得美食推荐信息&#xff0c;因此&#xff0c;设计一款安全高效的美食推荐系统极为重要。 为…...

基于php雪花算法工具类Snowflake -来自chatGPT

<?phpclass Snowflake {// 定义Snowflake算法的各个参数private $workerIdBits 5;private $datacenterIdBits 5;private $sequenceBits 12;private $workerIdShift;private $datacenterIdShift;private $timestampLeftShift;private $maxWorkerId;private $maxDatacente…...

怎么加密文件夹才更安全?安全文件夹加密软件推荐

文件夹加密可以让其中数据更加安全&#xff0c;但并非所有加密方式都能够提高极高的安全强度。那么&#xff0c;怎么加密文件夹才更安全呢&#xff1f;下面我们就来了解一下那些安全的文件夹加密软件。 文件夹加密超级大师 如果要评选最安全的文件夹加密软件&#xff0c;那么文…...

知识分享和Tomcat简单部署press应用

一、简述静态网页和动态网页的区别。 静态网页: 静态网页是指运行于客户端的程序、网页、组件、纯粹HTML格式的网页; 如果有涉及网页内容的修改&#xff0c;就要修改源文件&#xff0c;重新上传到服务器。而且当网站信息量很大的时候&#xff0c;网页制作和维护都非常困…...

回归预测 | MATLAB实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现SO-CNN-BiGRU蛇群算法优化卷积双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现SO-CNN-BiGRU蛇群算法…...

步入React前厅 - 组件和JSX

目录 扩展学习资料 购物车应用 编写React元素 /src/index.js 创建组件 /src/components/listItem.jsx /src/App.js 理解JSX【JavaScriptXML】 JSX是什么 JSX规则 /src/components/listItem.jsx 使用Fragments /src/App.js 为何要使用Fragments 表格中使用Fragme…...

SpringBoot整合Sfl4j+logback的实践

一、概述 对于一个web项目来说&#xff0c;日志框架是必不可少的&#xff0c;日志的记录可以帮助我们在开发以及维护过程中快速的定位错误。slf4j,log4j,logback,JDK Logging等这些日志框架都是我们常见的日志框架&#xff0c;本文主要介绍这些常见的日志框架关系和SpringBoot…...

IT 基础架构自动化

什么是 IT 基础架构自动化 IT 基础架构自动化是通过使用技术来控制和管理构成 IT 基础架构的软件、硬件、存储和其他网络组件来减少人为干预的过程&#xff0c;目标是构建高效、可靠的 IT 环境。 为什么要自动化 IT 基础架构 为客户和员工提供无缝的数字体验已成为企业的当务…...

Docker入门——保姆级

Docker概述 ​ —— Notes from WAX through KuangShen 准确来说&#xff0c;这是一篇学习笔记&#xff01;&#xff01;&#xff01; Docker为什么出现 一款产品&#xff1a;开发—上线 两套环境&#xff01;应用环境如何铜鼓&#xff1f; 开发 – 运维。避免“在我的电脑…...

MONGODB ---- Austindatabases 历年文章合集

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…...

菠萝头 pinia和vuex对比 pinia比vuex更香 Pinia数据持久化及数据加密

前言 毕竟尤大佬都推荐使用pinia&#xff0c;支持vue2和vue3&#xff01; 如果熟悉vuex&#xff0c;花个把小时把pinia看一下&#xff0c;就不想用vuex了 支持选项式api和组合式api写法pinia没有mutations&#xff0c;只有&#xff1a;state、getters、actionspinia分模块不…...

机器学习笔记 - 关于GPT-4的一些问题清单

一、简述 据报道,GPT-4 的系统由八个模型组成,每个模型都有 2200 亿个参数。GPT-4 的参数总数估计约为 1.76 万亿个。 近年来,得益于 GPT-4 等高级语言模型的发展,自然语言处理(NLP) 取得了长足的进步。凭借其前所未有的规模和能力,GPT-4为语言 AI​​设立了新标准,并为机…...

sql 参数自动替换

需求&#xff1a;看日志时&#xff0c;有的sql 非常的长&#xff0c;参数比较多&#xff0c;无法直接在sql 客户端工具执行&#xff0c;如果一个一个的把问号占位符替换为参数太麻烦&#xff0c;因此写个html 小工具&#xff0c;批量替换&#xff1a; 代码&#xff1a; <!…...

Linux——设备树

目录 一、Linux 设备树的由来 二、Linux设备树的目的 1.平台识别 2.实时配置 3.设备植入 三、Linux 设备树的使用 1.基本数据格式 2.设备树实例解析 四、使用设备树的LED 驱动 五、习题 一、Linux 设备树的由来 在 Linux 内核源码的ARM 体系结构引入设备树之前&#x…...

网络:从socket编程的角度说明UDP和TCP的关系,http和tcp的区别

尝试从编程的角度解释各种网络协议。 UDP和TCP的关系 从Python的socket编程角度出发&#xff0c;UDP&#xff08;User Datagram Protocol&#xff09;和TCP&#xff08;Transmission Control Protocol&#xff09;是两种不同的传输协议。 TCP是一种面向连接的协议&#xff0c…...

大数据技术之Hadoop:HDFS集群安装篇(三)

目录 分布式文件系统HDFS安装篇 一、为什么海量数据需要分布式存储 二、 分布式的基础架构分析 三、 HDFS的基础架构 四 HDFS集群环境部署 4.1 下载安装包 4.2 集群规划 4.3 上传解压 4.4 配置HDFS集群 4.5 准备数据目录 4.6 分发hadoop到其他服务器 4.7 配置环境变…...

移动开发最佳实践:为 Android 和 iOS 构建成功应用的策略

您可以将本文作为指南&#xff0c;确保您的应用程序符合可行的最重要标准。请注意&#xff0c;这份清单远非详尽无遗&#xff1b;您可以加以利用&#xff0c;并添加一些自己的见解。 了解您的目标受众 要制作一个成功的应用程序&#xff0c;你需要了解你是为谁制作的。从创建…...

2023年第二届网络安全国际会议(CSW 2023)

会议简介 Brief Introduction 2023年第二届网络安全国际会议(CSW 2023) 会议时间&#xff1a;2023年10月13日-15日 召开地点&#xff1a;中国杭州 大会官网&#xff1a;www.cybersecurityworkshop.org 2023年第二届网络安全国际会议(CSW 2023)由杭州电子科技大学&#xff0c;国…...

【100天精通python】Day23:正则表达式,基本语法与re模块详解示例

目录 专栏导读 1 正则表达式概述 2 正则表达式语法 2.1 正则表达式语法元素 2.2 正则表达式的分组操作 3 re 模块详解与示例 4 正则表达式修饰符 专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/qq_35831906/category_12375510.html 1 正则表达式概述 python 的…...

C++ 派生类成员的标识与访问——作用域分辨符

在派生类中&#xff0c;成员可以按访问属性分为以下四种&#xff1a; &#xff08;1&#xff09;不可访问成员。这是从基类私有成员继承下来的&#xff0c;派生类或是建立派生类对象的模块都无法访问到它们&#xff0c;如果从派生类继续派生新类&#xff0c;也是无法访问的。 &…...

SQL注入实操三(SQLilabs Less41-65)

文章目录 一、sqli-labs靶场1.轮子模式总结2.Less-41 stacked Query Intiger type blinda.注入点判断b.轮子测试c.获取数据库名称d.堆叠注入e.堆叠注入外带注入获取表名f.堆叠注入外带注入获取列名g.堆叠注入外带注入获取表内数据 3.Less-42 Stacked Query error baseda.注入点…...