linux篇【16】:传输层协议

news2025/2/23 5:35:05

目录

一.再谈端口号

1.端口号定义

2.端口号范围划分

(1)一共有 2^16 个端口

(2)认识知名端口号(Well-Know Port Number)

3.端口号和进程就是K V关系

4.netstat

(1)示例1: n 拒绝显示别名,能显示数字的全部转化成数字

(2)示例2: l 仅列出有在 Listen (监听) 的服务状态

(3)示例3: p 显示建立相关链接的程序名

5.pidof

二.UDP协议

1.UDP协议端格式

(1)UDP协议结构

(2)报头就是 带有位段的结构体 :

(3)添加报头的本质,其实就是拷贝对象

2.UDP的特点

3.面向数据报

4.UDP的缓冲区

5.UDP使用注意事项

6.基于UDP的应用层协议

三.TCP协议

1.TCP定义

2.TCP协议段格式

①如何封装和解包:

②如何分用

(1)详细介绍TCP协议段格式

(2)报文也是有类别的

(3)32位序号保证按序到达——URG

        ①32位序号保证按序到达到达:

        ②URG紧急指针标记位与紧急指针:

        ③URG应用场景——用来 获取服务器/主机 状态

3.可靠性问题:

(1)什么是不可靠:丢包,乱序,校验失败。。

(2)怎么确认一个报文是丢了还是没丢? ?(确认应答机制)

4.确认应答(ACK)机制

(1)32位序号/32位确认号

(2)为什么TCP报头有32位序号和32位确认号两组序号?常考

5.tcp的发送和接收缓冲区

(1)tcp有发送和接收缓冲区

(2)16位窗口大小——流量控制策略

(3)tcp正文长度由应用层决定

四.TCP三次握手

1.介绍

2.为什么要TCP三次握手

3.如何理解连接呢?

4.为什么是三次?

(1)三次握手一定能成功吗?

(2)为什么不是一次/二次握手?

(3)为什么是三次?

5.丢包解决——超时重传机制

(2)重复收到数据, 序列号可去重

(3)如果超时的时间如何确定? 

五.连接管理机制

2.listen的第2个参数

3.状态

(1)CLOSE_WAIT 半关闭状

 (2)TIME _WAIT


传输层
负责数据能够从发送端传输接收端。

一.再谈端口号

1.端口号定义

端口号(Port) 标识了一个主机上进行通信的不同的应用程序 ;
TCP/IP 协议中 , " IP", " 源端口号 ", " 目的 IP", " 目的端口号 ", " 协议号 " 这样一个五元组来标识一个通信 ( 可以通过 netstat -n 查看 );

2.端口号范围划分

(1)一共有 2^16 个端口

0 - 1023: 知名端口号, HTTP, FTP, SSH等这些广为使用的应用层协议, 他们的端口号都是固定的,端口号和进程是一一对应的。
1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号,例如8080, 就是由操作系统从这个范围分配的。

(2)认识知名端口号(Well-Know Port Number)

有些服务器是非常常用的, 为了使用方便 , 人们约定一些常用的服务器 , 都是用以下这些固定的端口号 :
—— ssh 服务器 , 使用 22 端口
—— ftp服务器 , 使用 21 端口
—— elnet服务器 , 使用 23 端口
—— http服务器 , 使用 80 端口
—— https服务器 , 使用 443
执行此命令 , 可以看到知名端口号
cat /etc/services

我们自己写一个程序使用端口号时, 要避开这些知名端口号

3.端口号和进程就是K V关系

1. 一个进程是否可以 bind 多个端口号?        ——可以。端口号:进程=K:V
2. 一个端口号是否可以被多个进程bind?        ——不可以

4.netstat

netstat是一个用来查看网络状态的重要工具 .
语法 netstat [ 选项 ]
功能 :查看网络状态
常用选项
         n 拒绝显示别名,能显示数字的全部转化成数字
        l 仅列出有在 Listen (监听) 的服务状态,-ntp就是只看established状态
        p 显示建立相关链接的PID和程序名
        t (tcp)仅显示tcp相关选项
        u (udp)仅显示udp相关选项
        a (all)显示所有选项,默认不显示LISTEN相关
通常使用:netstat -nltp

 

 

(1)示例1: n 拒绝显示别名,能显示数字的全部转化成数字

(2)示例2: l 仅列出有在 Listen (监听) 的服务状态

(3)示例3: p 显示建立相关链接的程序名

普通用户无法查看到建立相关链接的PID和程序名,只有root权限才能查看到

5.pidof

在查看服务器的进程 id 时非常方便 .
语法 pidof [ 进程名 ]
功能 :通过进程名 , 查看进程 id
UDP 协议
UDP 协议端格式

 

二.UDP协议

1.UDP协议端格式

(1)UDP协议结构

前8个字节是 UDP报头;剩下是报文

16位源端口号:自己的进程的端口号
16位目的端口号:要访问的目标进程的端口号

16位UDP长度:表示整个数据报(UDP首部+UDP数据)的最大长度;就是为了让UDP成为数据报式,而不是流式的。
        数据报:报文和报文之间有明显边界,因为有16位UDP长度
把一个一个的报文通过UDP长度分开一次接收一个。tcp字节流就需要一直等到读取长度到达encode报头长度才能进行。
16位UDP检验和:如果校验和出错,说明数据有问题,就会直接丢弃,暂时不考虑这个。

(2)报头就是 带有位段的结构体 :

(3)添加报头的本质,其实就是拷贝对象

把对象的成员变量填好,通过sizeof(udp_header)的大小拷贝进二进制,再强转成udp_header(udp_hdr)类型

2.UDP的特点

UDP传输的过程类似于寄信.
无连接: 知道对端的IP和端口号就直接进行传输, 不需要建立连接;
不可靠: (不可靠是特点不是缺点,中性词)没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方, UDP协议层也不会给应用层返回任何错误信息;不可靠可理解为:传输过程UDP报文丢失就真的丢失了。优点是:不需要为可靠性做更多的工作——>代码简单,维护简单,效率高等)
面向数据报: 不能够灵活的控制读写数据的次数和数量;
经典UDP的使用场景:直播

3.面向数据报

数据报:报文和报文之间有明显边界,因为有16位UDP长度

应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并;
举例:用UDP传输100个字节的数据:
如果发送端调用一次sendto, 发送100个字节, 那么接收端也必须调用对应的一次recvfrom, 接收100个字节; 而不能循环调用10次recvfrom, 每次接收10个字节;

4.UDP的缓冲区

UDP没有真正意义上的 发送缓冲区. 调用sendto会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;
UDP具有接收缓冲区,但是这个接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序一致(即:UDP报文大概率乱序,因为UDP不保证可靠性); 如果缓冲区满了, 再到达的UDP数据就会被丢弃;
UDP的socket既能读,也能写,因为UDP写和读数据的路径是两个,这个概念叫做 全双工

5.UDP使用注意事项

我们注意到, UDP协议首部中有一个16位的最大长度. 也就是说一个UDP能传输的数据最大长度是64K(包含UDP首部).
然而64K在当今的互联网环境下, 是一个非常小的数字.
如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装;这是没办法的

6.基于UDP的应用层协议

        NFS: 网络文件系统
        TFTP: 简单文件传输协议
        DHCP: 动态主机配置协议
        BOOTP: 启动协议 ( 用于无盘设备启动 )
        DNS: 域名解析协议
当然 , 也包括你自己写 UDP 程序时自定义的应用层协议

三.TCP协议

1.TCP定义

TCP全称为 " 传输控制协议 (Transmission Control Protocol"). 人如其名 , 要对数据的传输进行一个详细的控制 ;

2.TCP协议段格式

①如何封装和解包:

封装:封装和UDP一样,定义一个 TCP_header 的对象,把报头对象的各个值填上,再把这个对象拷贝到报文的前面即可;
解包:用先读取前20字节,读取其中的 4位首部长度4位首部长度*4 - 20 =  选项的大小 。

②如何分用

通过“16位目的端口号” 实现向上应用层交付实现分用。

(1)详细介绍TCP协议段格式

TCP报文包含报头和有效载荷。TCP报头包括前2字节和选项。报头是变长的:前20字节是标准长度,选项是变长的。

源/目的端口号: 表示数据是从哪个进程来 , 到哪个进程去 ;
32位序号/32位确认号 序号标定一个报文的编号;确认号标定 该确定号之前的报文全部收到 ,保证双向的全双工的确认应答机制。 详解见下面 4.—>(1)
4位TCP报头长度(4位首部长度 ): 表示该 TCP头部有多少个32bit(单位是4字节);此值是4bit位,则取值范围是0000~1111,即0~15,因为单位是4字节,所以TCP头部最大长度是15 * 4 = 60
因为标准长度有20,所以 4位首部长度 最少是 20 / 4字节 = 5=0101.即 4位首部长度 范围是0101~1111,20~60字节。则选项的大小就是0~40字节
6位标志位
•◆

(2)报文也是有类别的

16 位窗口大小: 应答本质就是要包含TCP报头,tcp报头可以有保存server接受能力的属性字段,叫做 16位窗口大小 详解见下面 5.—>(2)
16位校验和 : 发送端填充 , CRC 校验 . 接收端校验不通过 , 则认为数据有问题 . 此处的检验和不光包含 TCP 首部 , 也包含TCP 数据部分.(16位检验和是为了验证数据在传输过程有没有问题,有问题就丢掉。暂时不考虑这个属性)
16 位紧急指针 : 标识哪部分数据是紧急数据 ;
40 字节头部选项 : 暂时忽略 ;
ACK: 确认号是否有效
PSH: 提示接收端应用程序立刻从 TCP缓冲区把数据读走
RST: 对方要求重新建立连接 ; 我们把携带 RST 标识的称为 复位报文段
SYN: 请求建立连接 ; 我们把携带SYN标识的称为同步报文段,
FIN: 通知对方 , 本端要关闭了 , 我们称携带 FIN 标识的为 结束报文段
SYN:同步标记位,只要报文是建立链接的请求,SYN需要被设置为1,证明是链接请求的报文(sync的前三个字母)
FIN:该报文是一个断开链接的请求报文(finish)
ACK:确认标记位,设置为1表示该报文不仅仅是对历史报文的确认,同时也可以携带要发送的数据,一般在大部分正式通信的情况下ACK都是1

PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走
解释:之前我们是通过阻塞式调用read函数来读取数据,现在是通知以后再调用read,后者效率更高。
示例说明:假设接收缓冲区大小是100字节,超过了20字节会向上应用层通知来read,20叫接收数据的低水位线。当接收缓冲区内数据超过了20字节,PSH会让服务器操作系统通知上层已有数据,快来read。
 

 URG:紧急指针标记位。作用:该报文忽略序号,被上层直接读取处理。(该报文叫紧急指针报文)详情见三—>2—>(3)

RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段识。               

若最后的ACK丢失,则客户端不知道仍认为建立好连接了,则会继续发消息;服务器在未收到ACK时也意识到了这种问题,为了避免这种情况,服务器在未收到ACK时会连接重置,重新发送SYN+ACK应答,同时也把RST置为1

(3)32位序号保证按序到达——URG

        ①32位序号保证按序到达到达:

报文在发送的时候,是可能乱序到达的。这是不可靠的一种。
需要让我们的报文进行按序到达,如何做到?        ——32位序号保证按序到达。为报文标序号,接收缓冲区收到后排序即可。

        ②URG紧急指针标记位与紧急指针:

如果数据是必须在TCP中进行按序到达的话,也就是说如果有一些数据优先级更高,但是序号较晚,无法做到数据被有限紧急处理!

解决方案:使用 URG紧急指针标记位, URG标记为1,将优先级更高的报文忽略序号,被上层直接读取处理。(该报文叫紧急指针报文)

16位紧急指针:指向紧急指针报文的偏移量。紧急指针报文只能有一个字节

        ③URG应用场景——用来 获取服务器/主机 状态

客户端向服务器发数据,服务器可能因某种原因(例如内存不足)而无法接收消息或接收消息缓慢,这种情况下客户端想获知服务器的状态,就发送报文  URG紧急指针标记位 标为1,此时server在非常困难的情况下依旧优先接收了指向的一字节,在服务器内部通过已设置的某种逻辑得出一个状态码20(假设),通过 URG紧急指针标记位 把指向的一字节返回给客户端,客户端收到20状态码得知服务器无法正常工作原因是“内存不足”,再通知工作人员即可。

3.可靠性问题:

(1)什么是不可靠:丢包,乱序,校验失败。。

(2)怎么确认一个报文是丢了还是没丢? ?(确认应答机制)

答:我们如果收到了应答,我们确认是没丢,否则就是不确定。可靠性是指我们发出去的报文得到了对方应答是可靠的,没被应答的不能保证可靠。
详细解释:我们发出去的消息,我们如何得知对方是否收到?——只要得到对方的应答就意味着我刚刚发的消息对方100%收到了!
在长距离交互的时候,永远有一条最新的数据是没有应答的,所以没有百分之百可靠的协议!!但是可以做到局部百分之百可靠。
但是:只要发送的消息有对应的应答,我们就认为我们发送的消息,对方是收到的! !
确认应答机制保证了数据能被对方收到的问题

4.确认应答(ACK)机制

(1)32位序号/32位确认号

建立一个共识: tcp进行通信的时候,发送出去的报文一定会携带tcp报头!

解释下图:客户端发送一个有效载荷时一定是携带tcp报头的,并且数据都已经填好。假设随机生成的起始序号是1, 客户端发给服务器的整个报头+报文大小1000字节,则他占了1~1000序号,则32位序号就是1。服务器收到后为了应答客户端,则他会回复32位确认号是1001,它表示接收方已经收到了字节序号为 [1, 1000] 的数据,现在期望你发送字节序号为 1001 以及以后的数据。

32位序号/32位确认号序号标定一个报文的编号;确认号标定 该确定号之前的报文全部收到,之后的报文从该确定好下一个序号开始发 ,保证双向的全双工的确认应答机制。

例:服务器收到6个报文,32位序号分别是1,2,3,5,6,7,响应时返回给客户端的确认序号应该填4。解释:确认号是为了告诉客户端特定序号之前的报文全部收到,因为这里没收到4号报文,所以填4是告诉客户端4之前的报文全部收到,4没收到,客户端要从4号开始重新发。

(2)为什么TCP报头有32位序号和32确认号两组序号?常考

因为TCP协议是全双工的,我在给你发消息的同时,我也可以收消息。

解释:如果服务器想给你应答(填充确认序号),并且同时给你发消息(携带自己的序号)呢?——客户端给服务器发送“你吃饭了吗?”(填充32位序号),服务器给客户端发送应答“我吃饭了”(填充32位确认序号),同时发出“那你吃饭了吗?”(填充自己的32位序号

客户端用序号和对方的确认序号保证了从左向右的可靠性,服务器用自己的序号和对方的确认序号保证了从右向左的可靠性。这样保证了双向的全双工的确认应答机制。

(3) 

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

 

5.tcp的发送和接收缓冲区

(1)tcp有发送和接收缓冲区

IO类函数.本质其实都是拷贝函数
我们用write/send函数把数据拷贝到内核缓冲区后,tcp会在合适时候进行发送。内核缓冲区的数据什么时候发,发多少,出错了怎么办,要不要添加提高效率的策略——是由OS内的TCP自主决定的,所以TCP叫做传输控制协议!

上图可知,读写缓冲区用一个文件描述符业互不影响,可以说明 TCP通信是全双工的! !

(2)16位窗口大小——流量控制策略

在客户端向服务器发送数据包时,如果发送的太快了,导致server来不及接收怎么办?
——需要让client知道server的接受能力!
1.哪一个指标表示 server的接受能力呢?        ——接收缓冲区剩余空间的大小! 
2. client怎么知道? ?        ——发送都会有应答!应答本质就是要包含TCP报头,tcp报头可以有保存server接受能力的属性字段,叫做 16位窗口大小
3.server给client发报文,填充的窗口大小,填充的是自己的接收缓冲区剩余空间大小。
4. client——>server, server——> client,两个方向都是一样的

总结:双方的发送缓冲区基于得知对方接收缓冲区接收能力的条件下进行数据通信,根据对方每次应答中不断更新的窗口大小定期向对方发送合适的数据大小,这种策略就叫做流量控制策略。流量控制策略是双向的!

(3)tcp正文长度由应用层决定

tcp流式服务,所以没必要考虑正文长度,正文长度是需要应用层自己定协议的,比如我们写的encode和decode对整个序列化之后的字符串 9\r\n100 + 200\r\n 进行提取长度 

四.TCP三次握手

1.介绍

TCP三次握手:是 SYN,SYN+ ACK,ACK。SYN建立连接,SYN+ ACK 建立连接并确认连接,即应答,第三次ACK是客户端应答。


图中的线是斜的表明是要花时间的

2.为什么要TCP三次握手

——因为tcp是面向连接的。需要连接就用,udp肯定不用吧。

3.如何理解连接呢?

——大量的连接,OS就需要管理这些连接,如何管理? ?——先描述,在组织。建立连接结构体对象,再把结构体维护起来。维护连接是有成本的,花时间,花空间。

4.为什么是三次?

(1)三次握手一定能成功吗?

——不一定。tcp虽然是保证可靠性的,保证在通信时发送给对方的数据保证对方能收到。但不保证连接建立一定成功,是可以失败的。

(2)为什么不是一次/二次握手?

——不能。一次握手是指只发一个SYN就立马建立连接,这样容易受到攻击(SYN洪水)。SYN洪水:如果一个客户端故意发送很多SYN,则服务器需要维护对应的连接结构体,这样服务器会瞬间被占满,则导致正常连接无法连接。二次握手同理(SYN,SYN+ ACK)。多次发送SYN,服务器尽管多向客户端发送了ACK确认,但是客户端可以直接丢弃,没有任何代价的情况下让服务器维护一堆结构体从而打满。

(3)为什么是三次?

——理由1:奇数次握手可以把连接建立成功后最后一个报文丢掉的成本嫁接给客户端,最后一次确认由服务端来做,保证客户端比服务器先建立连接。如果一个客户端故意发送很多SYN,服务器收到后,短暂半连接维护连接结构体,然后返回给客户端SYN+ ACK 。客户端必须接收并返回ACK给服务器让服务器确认,如果客户端必不接收就无法发送ACK给服务器,服务器没收到则视为连接失败,服务器清除短暂半连接结构体;如果客户接收并返回ACK给服务器,则客户端也必须自己维护连接结构体,则服务器会拉客户端下水,则一个客户端想 SYN洪水 占满一个服务器很难,因为客户端的资源也在不断减少。这样就保证至少一个客户端想 SYN洪水 干翻一个服务器很难(以较小成本让服务器不那么容易被攻击到),但是也不是完全能避免,如果非常多客户端同时攻击也是不行的。

理由2:客户端和服务器都各自进行了一堆IO操作,这样以最小代价验证了全双工。

那客户端半链接不行?

5.丢包解决——超时重传机制

主机 A 发送数据给 B 之后 , 可能因为网络拥堵等原因 , 数据无法到达主机 B;
如果主机 A 在一个特定时间间隔内没有收到 B 发来的确认应答 , 就会进行重发 ;

(2)重复收到数据, 序列号可去重

 

但是 , 主机 A 未收到 B 发来的确认应答 , 也可能是因为 ACK 丢失了; 因此主机 B会收到很多重复数据(收到两个1~1000数据). 那么TCP协议能够识别出那些包是重复的包, 并且利用序列号把重复的丢弃掉, 做到去重的效果.
那么 , 如果超时的时间如何确定 ?

 

(3)如果超时的时间如何确定? 

        最理想的情况下, 找到一个最小的时间 , 保证 " 确认应答一定能在这个时间内返回 ".
        但是这个时间的长短, 随着网络环境的不同 , 是有差异的 .
        如果超时时间设的太长, 会影响整体的重传效率 ;
        如果超时时间设的太短, 有可能会频繁发送重复的包 ;
TCP 为了保证无论在任何环境下都能比较高性能的通信 , 因此会动态计算这个最大超时时间 .
        Linux中 (BSD Unix Windows 也是如此 ), 超时以 500ms 为一个单位进行控制 , 每次判定超时重发的超时
        时间都是500ms 的整数倍 .
        如果重发一次之后, 仍然得不到应答 , 等待 2*500ms 后再进行重传 .
        如果仍然得不到应答, 等待 4*500ms 进行重传 . 依次类推 , 以指数形式递增 .
        累计到一定的重传次数, TCP 认为网络或者对端主机出现异常, 强制关闭连接,服务器就会超时重传.

五.连接管理机制

在正常情况下, TCP 要经过三次握手建立连接 , 四次挥手断开连接。
 accept和三次握手没关系,只是把已经完成的三次握手提上来

四次挥手:一方向另一方发送FIN断开连接请求,对方ACK应答,对方同理,一个close对应一对挥手,共4次挥手。(特殊情况三次挥手:客户端向服务器发送FIN断开连接请求,对方ACK应答并且正好FIN置1也想断开,客户端在发送第三次ACK,这就是三次)

2.listen的第2个参数

list的第二个参数,叫做底层的全连接队列的长度,算法是: n+1, (n是用户传入的值)表示在不accept的情况你最多能够维护多少个链接。例如传2,就表示在不accept的情况最多能够维护3个链接,剩下的客户端请求的连接以半连接保持,当有全连接退出时,这个半连接才会变成全连接。
全连接维护的意义!

3.状态

 

服务端状态转化:
        [CLOSED -> LISTEN] 服务器端调用 listen 后进入 LISTEN 状态 , 等待客户端连接 ;
        [LISTEN -> SYN_RCVD] 一旦监听到连接请求 ( 同步报文段 ), 就将该连接放入内核等待队列中 , 并向客户端发送SYN 确认报文 .
        [SYN_RCVD -> ESTABLISHED] 服务端一旦收到客户端的确认报文 , 就进入 ESTABLISHED 状态 , 可以进行读写数据了.
        [ESTABLISHED -> CLOSE_WAIT] 当客户端主动关闭连接 (调用close), 服务器会收到结束报文段, 服务器返回确认报文段ACK并进入CLOSE_WAIT;
         [CLOSE_WAIT -> LAST_ACK] 进入CLOSE_WAIT后说明服务器准备关闭连接(需要处理完之前的数据); 当服务器真正调用close关闭连接时, 会向客户端发送FIN, 此时服务器进入LAST_ACK状态, 等待最后一个ACK到来(这个ACK是客户端确认收到了FIN)
        [LAST_ACK -> CLOSED] 服务器收到了对FINACK, 彻底关闭连接.
客户端状态转化:
[CLOSED -> SYN_SENT] 客户端调用 connect, 发送同步报文段 ;
[SYN_SENT -> ESTABLISHED] connect 调用成功 , 则进入 ESTABLISHED 状态 , 开始读写数据 ;
[ESTABLISHED -> FIN_WAIT_1] 客户端主动调用close, 向服务器发送结束报文段, 同时进入
FIN_WAIT_1;
[FIN_WAIT_1 -> FIN_WAIT_2] 客户端收到服务器对结束报文段的确认, 则进入FIN_WAIT_2, 开始等待服务器的结束报文段;
[FIN_WAIT_2 -> TIME_WAIT] 客户端收到服务器发来的结束报文段, 进入TIME_WAIT, 并发出LAST_ACK;
[TIME_WAIT -> CLOSED] 客户端要等待一个2MSL(Max Segment Life, 报文最大生存时间)的时间, 才会进入CLOSED状态.

 

 

(1)CLOSE_WAIT 半关闭状

无论是否accept,客户端只要close关闭,但服务器未close关闭,服务器一方就一直是 CLOSE_WAIT 状态(一方close,另一方未close,即半关闭状态):

 (2)TIME _WAIT

连接保持的状态下直接关闭服务器,服务器就成了主动关闭的一方,主动关闭的一方最终就会进入 TIME _WAIT(4次挥手已完成),过一会儿连接就会自动关闭

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/362312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql常用且易混淆函数整理

DATE_FORMAT(date,format) 函数中format的格式如下: 类型转化函数 为了进行数据类型转化,MySQL提供了CAST()函数,它可以把一个值转化为指定的数据类型。类型有:BINARY,CHAR,DATE,TIME,DATETIME,SIGNED,UNSIGNED 示例&a…

【前端】chatGPT教我写compose函数

0 前言 昨天希望实现一个通用的compose函数,能够接受同步函数与异步函数,并且通过异步函数同步执行来是吸纳compose函数中的所有参数函数能顺序执行。 比如compose(asyncFun3,syncFun2,asyncFun1,syncFunc0),四个函数能从右到作顺序执行&…

vue3+webpack5搭建项目

1、运行npm run dev报错: [webpack-cli] Failed to load E:\demoProject\vue3Webpack5\config\webpack.dev.js config [webpack-cli] Error: Cannot find module html-webpack-plugin 解决方案: 尝试了好多解决方案,都不可以。抱着试试的心…

2023年爆火的csgo搬砖项目详细拆解,steam搬砖长期稳定

不懂的同学可以听我下面慢慢道来 我的态度:存在即有意义,没有长久的赚钱项目,但是一定有长久赚钱的人。 我们团队也一直在做这个项目,赚钱是一定的,简单总结:执行力技巧量化。 开门见山 一、steam搬砖项…

Sqoop全部数据导入_将mysql数据库中的数据导入到hdfs中---大数据之Apache Sqoop工作笔记002

然后来看一下如何用sqoop导入数据,这里的导入指的是从其他数据源导入到hdfs,反过来是导出 然后看一下首先准备一下数据 去创建数据库company ,创建表staff, 然后插入数据 插入两行数据测试用 \ 然后查询一下use company 然后查询一下看看结果

整车电源的几种模式:OFF/ACC/RUN/CRANK

本文框架1.前言2. 四种电源模式2.1 OFF模式2.2 ACC模式2.3 ON模式2.4 CRANK模式3. KL15/KL301.前言 在诊断或者网络管理相关模块开发对客户的需求进行梳理时,经常会看到客户对不同车辆模式下处理策略的需求,如果前期没接触过这几种模式,可能…

基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试(中篇)

3.2 SPI硬件时序方式 上面的3.1小节是采用SPI模拟时序驱动SD NAND,STM32本身集成有SPI硬件模块,可以直接利用STM32硬件SPI接口读写。 下面贴出底层的适配代码。 上面贴出的驱动代码里,已经将驱动接口部分和协议逻辑部分区分开了,替…

设计模式C++实现20: 桥接模式(Bridge)

部分内容参考大话设计模式第22章;本实验通过C语言实现。 一 基本原理 意图:将抽象部分和实现部分分离,使它们都可以独立变化。 上下文:某些类型由于自身的逻辑,具有两个或多个维度的变化。如何应对“多维度的变化”…

掌握MySQL分库分表(六)解决主键重复问题--Snowflake雪花算法

文章目录问题及需求常用ID解决方案数据库自增IDUUIDRedis发号器Snowflake雪花算法分布式 ID 生成算法Snowflake原理关于bit与byte雪花算法的位数Snowflake必须注意的地方全局唯⼀、不能重复保证各个系统时间一致Snowflake雪花算法实现雪花算法测试结果问题及需求 单库下⼀般使…

模块Model

定义 包含一系列数据,函数,类的文件,通常以.py结尾 作用 让相关的数据,函数,类有逻辑的组织 第一种调用方法直接通过import导入模块名 首先创建模块module01.py import timedef print_nowtime():"""…

sqlserver复制远程数据库到本地

文章目录前言一、前置知识在微软的SQL Server 2000 数据库有三种类型的文件:主要数据文件:(扩展名.mdf是 primary data file 的缩写)次要数据文件(扩展名.ndf是Secondary data files的缩写)事务日志 &#…

【数据结构】——树和二叉树的概念

目录 1.树概念及结构 1.1树的概念 1.2 树的相关性质 1.3 树的表示 1.4 树在实际中的运用(表示文件系统的目录树结构) 2.二叉树概念及结构 2.1二叉树概念 2.2 特殊的二叉树 2.3 二叉树的性质 1.树概念及结构 1.1树的概念 树是一种非线性的数据结构…

Retrofit+Hilt后端请求小项目2--依赖与准备工作

目录依赖处理settings.gradlebuild.gradle(project:app)build.gradle(module:app)准备工作接口安装 JSON 转 kotlin 插件获取 JSON依赖处理 settings.gradle 首先在此指定使用 hilt 依赖时的版本 pluginManagement {repositories {gradlePluginPortal()google()mavenCentral…

服务稳定性保障手段与规范

服务的稳定性,对于任何一个在线提供服务给用户的公司来说,都是非常重要的。任何一次线上事故,都可能会给公司带来显而易见的损失。因为相比于其他部门,负责基础技术、公共服务的同学,发生事故的时候很容易暴露在风口浪…

Kaldi语音识别技术(七) ----- 训练GMM

Kaldi语音识别技术(七) ----- GMM 文章目录Kaldi语音识别技术(七) ----- GMM训练GMMtrain_mono.sh 用于训练GMM训练GMM—生成文件训练GMM—final模型查看训练GMM—final.occs查看训练GMM—对齐信息查看训练GMM—fsts.*.gz查看训练GMM—tree决策树查看align_si.sh 用于对齐训练G…

Cookies与Session会话技术详解

引言:日常生活中,人和人之间沟通交流,涉及到一个词----会话,软件中一样存在会话,如:网购登录,访问公司OA系统也是不断的会话,软件中如何管理浏览器客户端和服务端之间会话过程中的会话数据呢&am…

oscp_靶场练习_Lame

oscp_靶场练习_Lame 1. nmap扫描: └─# nmap 10.10.10.3 Starting Nmap 7.92 ( https://nmap.org ) at 2023-02-20 23:21 EST Nmap scan report for 10.10.10.3 Host is…

switch的使用细节

1.switch的基本语法 switch(表达式){ case 常量1: 语句块1; break; case 常量2: 语句块2; break; … case 常量n: 语句块n; break; default: default语句块; break; } (1)switch关键字,表示switch分支 (2)表达式对应一…

web自动化测试中的几个定位方法

1. id定位 # id定位,属性 操作 返回 webELement 对象 ele1 driver.find_element_by_id("kw") print(ele1)2. 标签名定位 tag_name 不能唯一的找到特定的元素 ele2 driver.find_element_by_tag_name("input") # (译:泰格.内幕…

数组-二分查找-搜索插入位置/在排序数组中查找元素的第一个和最后一个位置/x 的平方根/有效的完全平方数

二分查找 35搜索插入位置 https://leetcode.cn/problems/search-insert-position/submissions/ class Solution:def searchInsert(self, nums: List[int], target: int) -> int:l 0r len(nums)-1# // 整数除法 int /浮点数除法while(l<r):mid l (r - l)//2if nums…