第三十篇:TCP连接断开过程,从底层说明白,TCP系列五

上一篇《第二十九篇:图解TCP三次握手,看过不会忘,从底层说清楚,TCP系列四》说了TCP的三次握手,接下来我将讲解TCP四次挥手。

既然有连接就有断开,谈到这里,有的同学可能会想,不就是TCP的断开吗?简单,四次挥手解决问题,只要了解了四次的挥手过程就掌握了TCP的断开,我只能说:同学,too young,too simple;且让我提出几个问题去思考:

  1. 连接断开是谁先发起的?
  2. 如果断电/断网了,连接会断开吗?
  3. 程序奔溃了,连接会断开吗?
  4. 什么情况下没有四次挥手连接也会断开?
  5. 连接断开发生在应用层还是传输层?

只有掌握了断开的底层逻辑,才能在工作中遇到问题不慌不忙,做到游刃有余的解决问题,轻松拿高薪。

一、理想状态下,一个 TCP 连接可以被长期保持

前面我们说到,TCP连接其实就是通过三次握手,在通信双方的主机里面保存对应的通信信息,即⽤于保证可靠性和流量控制维护的某些状态信息称为连接也可以理解成“通信线路”这些状态信息包括Socket、序列号和窗⼝⼤⼩如下图所示:

  1. 套接字:由 IP 地址、端⼝号以及传输层协议(TCP或UDP)组成
  2. 序列号:⽤来解决乱序问题等
  3. 窗⼝⼤⼩:⽤来做流量控制

所以理论上如果通信双方的“连接信息”不变一直保存在双方主机则理论连接会被长期保存

但是现实却往往是很残酷的连接经常或被动断开比如断电TCP连接信息缓存丢失导致连接遭到损坏);或一方主机根据情况主动断开比如不想浪费资源内存和断开是有限的),一方主机在发送完资源后用程序主动关闭连接

二、那么下面就让我们一起来梳理哪些情况会发生连接断开

  1. 通信双方信息交互完后,一方主动调用TCP软件的“连接断开方法”进行TCP四次挥手断开连接
  2. 程序奔溃、使用CTRL + C、kill -9 方法杀死进程
  3. 硬件奔溃:主机损坏、断网等
  4. 一方断电或宕机
  5. 防火墙关闭连接
  6. 其他情况

三、会正常执行TCP四次挥手断开连接的情况有下面几种

1.通信双方信息交互完后,一方主动调用TCP软件的“连接断开方法”

比如,应用程序使用HTTP协议进行信息交互,当交互完后,客户端因为信息发送完成,主动调用close方法或实现http的程序包因为检测到通信双方长时间没有信息交互而主动发起连接断开,这些都发生在应用层,就是程序员开发的应用程序。

2.程序奔溃、使用CTRL + C、kill -9 方法杀死进程

因为应用程序没有主动调用TCP软件的断开流程,将有OS系统自动触发TCP四次挥手断开流程。

3.防火墙关闭连接

防火墙触发TCP四次挥手断开流程。

四、TCP正常断开的四次挥手流程

1. 客户端打算关闭连接,此时会发送⼀个 TCP ⾸部 FIN 标志位被置为 1 的报⽂,也即 FIN 报⽂,之后客户端进⼊ FIN_WAIT_1 状态。

2. 服务端收到该报⽂后,就向客户端发送 ACK 应答报⽂,接着服务端进⼊ CLOSED_WAIT 状态。

3. 客户端收到服务端的 ACK 应答报⽂后,之后进⼊ FIN_WAIT_2 状态。

4. 等待服务端处理完数据后,也向客户端发送 FIN 报⽂,之后服务端进⼊ LAST_ACK 状态。

5. 客户端收到服务端的 FIN 报⽂后,回⼀个 ACK 应答报⽂,之后进⼊ TIME_WAIT 状态,之后的2MSL时间内都是time_wait状态。

6. 服务器收到了 ACK 应答报⽂后,就进⼊了 CLOSED 状态,⾄此服务端已经完成连接的关闭。

7. 客户端在经过 2MSL ⼀段时间后,⾃动进⼊ CLOSED 状态,⾄此客户端也完成连接的关闭。

你可以看到,每个⽅向都需要⼀个 FIN 和⼀个 ACK,因此通常被称为四次挥⼿。

而在日常的tcp连接断开中,一般只有三次挥手,这是因为如果第二次与第三次挥手之间没有数据发送,那么被动断开连接的一方就可能会把第二次的 ACK 与 第三次的 FIN 合并为一次挥手。四次挥手就会变成三次挥手。

五、为何需要四次挥手而不是像建立连接一样三次挥手

如果第二次与第三次挥手之间没有数据发送,那么被动断开连接的一方就可能会把第二次的 ACK 与 第三次的 FIN 合并为一次挥手。四次挥手就会变成三次挥手

  1. 延时确认,捎带确认

在建立连接的第三次握手的时候有可能带上数据在连接断开的四次挥手的第二次挥手即连接断开被动方在接收到FIN报文的时候会给断开主动方发送ACK报文这个报文不会立即发送出去,而是等待200ms(推荐值,但是这个值不能高于500ms),如果在这段时间有用户数据需要发送则一同随着这个ACK发送。

六、为何需要time_wait状态

主动发起关闭连接的⼀⽅,才会有 TIME-WAIT 状态。TIME _WAIT状态也称为2MSL等待状态。

MSL(Maximum Segment Lifetime)是最大报文段生存时间,它是任何报文段被丢弃前在网络内生存的最长时间,RFC1122建议是2分钟,但BSD传统实现采用了30秒。

当连接转移到TIME_WAIT状态时,即连接主动关闭时,定时器启动,为两倍的MSL。定时器超时,这时才能重新使用之前连接使用的插口源IP端口和目的IP和端口的组合即插口也叫四元组。这也是为了避免一些意想不到的边界情况。

        1. time_wait帮助连接正确关闭

断开连接的被动端要确保fin报文正确到达主动端需要主动端回复ack报文通知被动端fin报文已经成功到达否则被动端会继续发送fin报文如果没有time_wait,主动端接收到fin报文回复ack报文然后进入closed状态如果ack报文丢失被动端超时重发fin报文得到的将是RST报文这不符合正确关闭的目标

rst 报文在客户端会显示报错信息Connection closed by foreign host

         2. time_wait防止两端在就连接未关闭完全期间在同一个插口建立新连接导致新旧数据错乱

如果没有time_wait,主动端的ack丢失同时被动端再次发送fin报文此时主动端在该插口的状态为关闭建立新的连接可能会导致迟到的fin报文使新连接困惑进而导致异常

七、为何是等待2MSL?

因为断开发起方主动端回复ack报文在网络上的过期时间是一个MSL被动端在 1MSL 内没有收到主动端发出的 ACK 确认报文,就会再次向主动端发出 FIN 报文,被动端重发fin报文在网络上的过期时间也是一个MSL如果2MSL时间内没有再次收到被动端发送来的fin报文则主动端认为被动端已经接收到ack报文关闭了连接则主动端也关闭连接

2MSL时间段内如果断开主动方主动端再次接收到被动端的fin报文,说明服务器端由于各种原因没有接收到客户端发出的 ACK 确认报文。客户端再次向服务器端发出 ACK 确认报文,计时器重置,重新开始 2MSL 的计时。直到2MSL时间内未收到fin报文正确关闭连接

假设被动端的fin报文始终没有收到ack2MSL内主动端也没收到fin报文则被动端在重试了一定次数后也会断掉连接如果在重试过程中fin报文又到达主动端而主动端也过了2MSL则此时被动端将收到RST报文使被动端的连接关闭

TCP定义

  1. 2MSL时间内连接上的插口不能再继续建立连接
  2. 平静时间

对于来自某个插口的较早连接的迟到报文段, 2MSL等待可防止将它解释成使用相同插口

对的新连接的一部分。但这只有在处于 2 M S L等待连接中的主机处于正常工作状态时才有效。

如果使用处于2 M S L等待端口的主机出现故障,它会在 M S L秒内重新启动,并立即使用故

障前仍处于2 M S L的插口对来建立一个新的连接吗?如果是这样,在故障前从这个连接发出而迟到的报文段会被错误地当作属于重启后新连接的报文段。无论如何选择重启后新连接的初

始序号,都会发生这种情况。

为了防止这种情况,RFC 793指出T C P在重启动后的M S L秒内不能建立任何连接。这就称

为平静时间(quiet time)。

只有极少的实现版遵守这一原则,因为大多数主机重启动的时间都比MSL秒要长。

八、定时器

        1.建立连接定时器 --- Connection-establishment Timer

如果client在连接server的时候, 在发送SYN的时候, 会启动一个定时器(在 3.10 版本中首次超时时间是 1 s,一些老版本中是 3 s。),如果SYN包丢失了, 那么1秒以后会重新发送SYN包的(当然还会启动一个新的定时器, 设置成2秒超时),当然也不会一直没完没了的发SYN包, 在/proc/sys/net/ipv4/tcp_syn_retries 可以设置到底要重新发送几次SYN包。

        2. 重传定时器---Retransmission Timer

对于TCP发送出去的数据包, 需要等待对端发来ACK才能从内存里面删除, 那么如果对端没有发送ACK怎么办? 重传。

在发送数据的同时,再设置一个超时时间RTO,如果在这个超时时间内, 没有收到ACK,那么就重传刚才发送的数据。

        3. FIN_WAIT_2定时器

在主动关闭的一端调用完close以后(发FIN包给对端, 并且收到对端对FIN的ACK)则进入到FIN_WAIT_2状态, 那么这个时候如果和对端之间的网络坏了或者对端程序有问题了一直不close, 或者对端机器直接掉电了, 本端不能一直傻等, 所以就需要这个定时器.

如果在这个定时器超时的时候,还是没收到对端的FIN包, 那么不好意思, 不等了, 直接释放这个链接。

这个定时器的时间是多少呢?可以从/proc/sys/net/ipv4/tcp_fin_timeout里面看到。

        4. 2MSL定时器

2MSL时间段内如果断开主动方主动端再次接收到被动端的fin报文,说明服务器端由于各种原因没有接收到客户端发出的 ACK 确认报文。客户端再次向服务器端发出 ACK 确认报文,计时器重置,重新开始 2MSL 的计时。直到2MSL时间内未收到fin报文正确关闭连接

        5. 坚持定时器---Persist Timer

如果某一时刻,一方发现自己的 socket read buffer 满了,无法接受更多的TCP data,此时就是在接下来的发送包中指定通告窗口的大小为0,这样对方就不能接着发送TCP data了。如果socket read buffer有了空间,可以重设通告窗口的大小在接下来的 TCP segment 中告知对方。可是万一这个 TCP segment 不附带任何data,所以即使这个segment丢失也不会知晓(ACKs are not acknowledged, only data is acknowledged)。对方没有接受到,便不知通告窗口的大小发生了变化,也不会发送TCP data。这样双方便会一直僵持下去。

TCP协议采用这个机制避免这种问题:TCP使用了零窗口探测技术(Zero Window Probe,缩写为ZWP),也就是说,接收端在接收窗口变为0后会通知发送端,发送端发现接收端窗口大小变为0,会启动一个定时器,这个定时器就是Persist Timer,在定时器超时后,会发探测报文给接收方,让接收方来ack他的Window尺寸,一般这个值会设置成3次,每次大约30-60秒(不同的实现可能会不一样)。如果3次过后还是0的话,有的TCP实现就会发RST把链接断了。

        6. 保活计时器---Keepalive Timer

如果客户端和服务端长时间没有数据交互,那么需要保活定时器来判断是否对端还活着,但是这个其实很不实用,因为默认是2小时没有数据交互才探测,时间实在是太长了。

具体实现方法:TCP每隔一段时间(tcp_keepalive_intvl)会发送一个特殊的 Probe Segment,强制对方回应,如果没有在指定的时间内回应,便会重传,一直到重传次数达到 tcp_keepalive_probes 便认为对方已经crash了。

# TCP KeepAlive 机制,保活时间、保活时间间隔和保活探测次数

net.ipv4.tcp_keepalive_time

net.ipv4.tcp_keepalive_intvl

net.ipv4.tcp_keepalve_probes

在 Linux 上可以通过如下文件查看

cat /proc/sys/net/ipv4/tcp_keepalive_time   

cat /proc/sys/net/ipv4/tcp_keepalive_intvl   

cat /proc/sys/net/ipv4/tcp_keepalive_probes

默认设置是 7200 秒(2 小时)、75 秒和 9 次探测。

如果使用 TCP 自身的 keep-Alive 机制,在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个“死亡”连接。

这个时间是怎么计算出来的呢?

其实是通过 2 小时,加上 75 秒乘以 9 的总和。

如果你真的要确认对端是否活着, 那么应该在应用层自己实现心跳包,而不是依赖于这个保活定时器。

实际上,对很多对时延要求敏感的系统中,这个时间间隔是不可接受的。

如果开启了 TCP 保活,需要考虑以下⼏种情况:

第⼀种,对端程序是正常⼯作的。当 TCP 保活的探测报⽂发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下⼀个 TCP 保活时间的到来。

第⼆种,对端程序崩溃并启。当 TCP 保活的探测报⽂发送给对端后,对端是可以响应的,但由于没有该连接的有效信息,会产⽣⼀个 RST 报⽂,这样很快就会发现 TCP 连接已经被᯿置。

第三种,是对端程序崩溃,或对端由于其他原因导致报⽂不可达。当 TCP 保活的探测报⽂发送给对端后,⽯沉⼤海,没有响应,连续⼏次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

        7. 延迟应答定时器 --- delayed ACK timer

顾名思义, 这个定时器是在延迟应答的时候使用的。

为什么要延迟应答呢?

比如客户端发一段数据给服务端, 服务端本应该立刻回ACK给客户端的, 延迟应答是为了提高网络传输的效率, 比如服务端收到客户端的数据后, 不是立刻回ACK给客户端, 而是等一段时间(一般最大200ms),这样如果服务端要是有数据需要发给客户端,那么这个ACK就和服务端的数据一起发给客户端了, 这样比立即回给客户端一个ACK节省了一个数据包。

参考

【tcp】TCP协议中的7种定时器 - 简书

  TCP协议的超时详解 - 简书

九、非四次挥手连接损坏

1)硬件奔溃:主机损坏、断网等

2)一方断电或宕机

1. 没有数据传输的时候主机奔溃

如果对方在开启了TCP keepalive 保活那么如果在机器停机期间如果对方发送了保活探测报文此时未奔溃端的探测报文会石沉大海,不会被响应,连续几次后,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。

# TCP KeepAlive 机制,保活时间、保活时间间隔和保活探测次数

net.ipv4.tcp_keepalive_time

net.ipv4.tcp_keepalive_intvl

net.ipv4.tcp_keepalve_probes

在 Linux 上可以通过如下文件查看

cat /proc/sys/net/ipv4/tcp_keepalive_time   

cat /proc/sys/net/ipv4/tcp_keepalive_intvl   

cat /proc/sys/net/ipv4/tcp_keepalive_probes

2. 有数据传输的时候主机奔溃

数据会超时重传,数据报文的重传次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了,一般就是 ETIMEOUT 错误状态码。

那具体重传几次呢?

在 Linux 系统中,提供一个叫 tcp_retries2 配置项,默认值是 15可以通过

Cat /proc/sys/net/ipv4/tcp_retries2 查看和设置

这个内核参数是控制,在 TCP 连接建立的情况下,超时重传的最大次数。

不过 tcp_retries2 设置了 15 次,并不代表 TCP 超时重传了 15 次才会通知应用程序终止该 TCP 连接,内核还会基于「最大超时时间」来判定。

超时重传阶段每一轮的超时时间都是倍数增长的,比如第一次触发超时重传是在 2s 后,第二次则是在 4s 后,第三次则是 8s 后,以此类推。

但是这个超时时间不会无限增加下去会受到最大超时时间的限制超时时间的计算根据一下公式来计算

其中rto_base为200ms;TCP_RTO_MAX为120000ms。

机器恢复后因为异常导致本方TCP连接信息丢失,重启完成后,收到之前 TCP 连接的报文,都会回复 RST 报文,以断开连接。

十、解决连接断开过程中的问题

1. time_wait 堆积过多如何解决

危害

① 内存资源的占用

 对端口资源的占用,一个 TCP 连接至少消耗「发起连接方」的一个本地端口

要直到端口资源是有限的只有65536),如果被time_wait占用过多,占满了所有端口资源,则会导致无法创建新连接,影响正常的使用

原因

可能是高并发情况下高并发让服务器在短时间范围内同时占用大量端口而业务处理+传输数据的时间 远远小于 TIME_WAIT的2MSL超时时间导致很多time_wait对接影响其他正常的连接

解决

① 修改内核参数---设置time_wait的连接重用或快速回收

  • net.ipv4.tcp_tw_reuse = 1

表示开启重用。允许将time_wait sockets重新用于新的TCP连接,默认为0,表示关闭;

因为重用插口新连接不能处理旧数据TCP需要能判断到达的数据是否为旧数据实现原理是根据时间戳判断是否是延迟的数据,如果是,则丢弃。要实现这个功能就需要开启TCP对时间戳的支持这个内核参数是:net.ipv4.tcp_timestamps=1(默认即为 1,开启);这个时间戳的字段是在 TCP 头部的「选项」⾥,⽤于记录 TCP 发送⽅的当前时间戳和从对端接收到的最新时间戳。

由于引⼊了时间戳,我们在前⾯提到的 2MSL 问题就不复存在了,因为复的数据包会因为时间戳过期被⾃然丢弃,不会对新旧数据产生混淆

  • net.ipv4.tcp_tw_recycle = 1

表示开启TCP连接中time_wait sockets的快速回收,默认为0,表示关闭。

  • net.ipv4.tcp_max_tw_buckets

这个值默认为 18000,当系统中处于 TIME_WAIT 的连接⼀旦超过这个值时,系统就会将后⾯的 TIME_WAIT 连接状态重置。

这个⽅法过于暴⼒,⽽且治标不治本,带来的问题远⽐解决的问题多,不推荐使⽤。

 客户端:短链接改长连接

HTTP 请求的头部, connection 设置为 keep-alive, 保持存活一段时间;

长连接从根本上减少了关闭连接的次数,减少了TIME_WAIT状态的产生数量,在高并发的系统中非常有效,现在的浏览器, 一般都这么进行了 。

③ 缩减 time_wait 时间

例如: 设置为 1 MSL(即, 2 mins)

 不主动关闭连接

不主动关闭socket,就不会产生TIME_WAIT状态

 程序中使⽤ SO_LINGER

我们可以通过设置 socket 选项,来设置调⽤ close 关闭连接⾏为。

struct linger so_linger;

so_linger.l_onoff = 1;

so_linger.l_linger = 0;

setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger,sizeof(so_linger));

如果 l_onoff 为⾮ 0, 且 l_linger 值为 0,那么调⽤ close 后,会⽴该发送⼀个 RST 标志给对端,该 TCP 连接将跳过四次挥⼿,也就跳过了 TIME_WAIT 状态,直接关闭。

但这为跨越 TIME_WAIT 状态提供了⼀个可能,不过是⼀个⾮常危险的⾏为,不值得提倡。

参考

服务器出现大量TIME_WAIT状态怎么解决_最大进程打开文件timewait-CSDN博客

2. close_wait 堆积过多如何解决

危害

使服务端的服务不可用

原因

被服务端没有发送fin报文导致没有发送的原因一般都是程序因为被阻塞比如调用远程资源或者异常代码死循环让客户端超时关闭客户端发送关闭请求服务端回复ack但是由于各种原因导致服务端程序一直在运行阻塞无法发出fin报文

解决

① 修改内核参数

开启TCP保活检测

② 资源的访问一定要设置访问超时时间

比如数据库访问超时第三方资源访问超时等

③ 代码要规范资源要牢记释放

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

log4j 和 logback 冲突解决

很多springboot starter自带logback 如果我们要用log4j就要把logback排除掉 点idea的maven侧栏工具的分析依赖关系 然后我们要选中我们有冲突的模块,搜索logback 这时候我们发现有logback相关的依赖,在点一下,我们就在右边发现,原…

STM32--I2C通信

对于I2C通信会分为两大块来讲解,第一块,就是介绍协议规则,然后用软件模拟的形式来实现协议,第二块,就是介绍STM32的12C外设,然后用硬件来实现协议,因为12C是同步时序,软件模拟协议也非常方便。 在学12C之前,我们已经学习了串口通信&#xff…

openlayers 封装加载本地geojson数据 - vue3

Geojson数据是矢量数据,主要是点、线、面数据集合 Geojson数据获取:DataV.GeoAtlas地理小工具系列 实现代码如下: import {ref,toRaw} from vue; import { Vector as VectorLayer } from ol/layer.js; import { Vector as VectorSource } fr…

蓄电池在线监测系统 各大UPS铅酸蓄电池监测 保障安全

蓄电池的不断普及,确实推动了蓄电池监控和管理技术的持续升级。蓄电池检测系统的研发为我们带来了诸多好处,这些好处主要体现在以下几个方面: 一、提高蓄电池管理的智能化水平 蓄电池检测系统通过实时监测蓄电池的电压、电流、温度等关键参数…

ZEISS ATOS Q蓝光三维扫描仪高效把控零件质量检测【上海沪敖3D】

位于Bengaluru的施耐德电气工厂拥有一流的计量设备,可以检测所有供应商的零件。当时,他们在使用一款激光扫描设备进行质量检测,但是,该设备不便于携带,且检测时需要喷涂大量的显影液。此外,它需要被安装在夹…

docker基础使用创建固定硬盘大小为40G的虚拟机

在docker中创建的服务器,匹配出容器id,服务器ip,服务器核数,服务器内存,服务器硬盘空间 for i in $(docker ps | grep -aiE web | awk {print $1});do echo $i; docker inspect $i|grep -aiE ipaddr|tail -1|grep -ai…

医院信息化与智能化系统(7)

医院信息化与智能化系统(7) 这里只描述对应过程,和可能遇到的问题及解决办法以及对应的参考链接,并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图,可以试试PlantUML,告诉GPT你的文件结构,让他给你对应的…

最新PHP网盘搜索引擎系统源码 附教程

最新PHP网盘搜索引擎系统源码 附教程,这是一个基于thinkphp5.1MySQL开发的网盘搜索引擎,可以批量导入各大网盘链接,例如百度网盘、阿里云盘、夸克网盘等。 功能特点:网盘失效检测,后台管理功能,网盘链接管…

使用freemarker实现在线展示文档功能开发,包括数据填充

首先,在这个独属于程序员节日的这一天,祝大家节日快乐【求职的能找到心仪的工作,已经工作的工资翻倍】。 ---------------------------------------------------------------回到正文-----------------------------------------------------…

状态栏黑底白字后如何实现圆角以及固定状态栏

如何实现如下效果: 上述是将状态栏实现黑底白字+圆角+状态栏固定的逻辑 具体代码patch如下: From 6a3b8ed5d3f49a38d8f9d3e488314a66ef5576b8 Mon Sep 17 00:00:00 2001 From: andrew.hu <andrew.hu@quectel.com> Date: Fri, 18 Oct 2024 16:43:49 +0800 Subject: [P…

Next.js14快速上手

文章目录 ***客户端***什么是Next项目在线地址官方文档项目创建查看项目目录结构app属于根目录 ***服务端***vercel数据库prisma 客户端 什么是Next Next.js 是一个用于构建全栈 Web 应用程序的 React 框架。您可以使用 React Components 来构建用户界面&#xff0c;并使用 Ne…

Unity引擎:游戏开发的核心力量

目录 引言 Unity引擎的发展历程 早期发展 跨平台支持 Unity引擎的核心特性 易用性 社区支持 跨平台能力 Unity在游戏开发中的应用 移动游戏 独立游戏 3A游戏 Unity的未来展望 高级图形和渲染技术 扩展现实&#xff08;XR&#xff09;支持 云服务和多人游戏 结论…

excel中,将时间戳(ms或s)转换成yyyy-MM-dd hh:mm.ss或毫秒格式

问题 在一些输出为时间戳的文本中&#xff0c;按照某种格式显示更便于查看。 如下&#xff0c;第一列为时间戳(s)&#xff0c;第二列是转换后的格式。 解决方案&#xff1a; 在公式输入框中输入&#xff1a;yyyy/mm/dd hh:mm:ss TEXT((A18*3600)/8640070*36519, "yyy…

Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks

Abstract 图像到图像转换是一类视觉和图形问题&#xff0c;其目标是使用对齐图像对的训练集来学习输入图像和输出图像之间的映射。 然而&#xff0c;对于许多任务&#xff0c;配对训练数据将不可用。 我们提出了一种在没有配对示例的情况下学习将图像从源域 X 转换到目标域 Y …

Android 15自定义设置导航栏与状态栏,EdgeToEdge适配

背景&#xff1a;android api 35&#xff0c;activity设置EdgeToEdge.enable((ComponentActivity) this)前提下 一、设置导航栏与状态栏颜色 设置的状态栏颜色&#xff0c;只需要设置fitsSystemWindows跟setOnApplyWindowInsetsListener xml设置&#xff1a; 代码&#xff1a;…

没有AWS账号能不能在手机上使用AWS服务吗?

关于“没有AWS账号能不能在手机上使用AWS服务”这个问题&#xff0c;答案是不行的。要使用AWS&#xff08;亚马逊云服务&#xff09;提供的云服务&#xff0c;无论是在电脑还是手机上&#xff0c;都必须先创建一个AWS账号。AWS提供的各种云计算资源&#xff0c;比如EC2&#xf…

51单片机——OLED显示图片

取模软件&#xff1a;链接:https://pan.baidu.com/s/1UcrbS7nU4bsawNxsaaULfQ 提取码:gclc 1、如果图片大小和格式不合适&#xff0c;可以先用Img2Lcd软件进行调整图片大小&#xff0c;一般取模软件使用的是.bmp图片&#xff0c;可以进行输出.bmp格式。软件界面如下&#xff1…

ubuntu编译kaldi和vosk

文章目录 前言一、开源框架的选取二、kaldi编译三、编译vosk方案一方案二 前言 由于工作需要语音识别的功能&#xff0c;环境是在linux arm版上&#xff0c;所以想先在ubuntu上跑起来看一看&#xff0c;就找了一下语音识别的开源框架&#xff0c;选中了vosk这个开源库&#xf…

java控制台打印乘法口诀表

目录 前言具体代码完整代码 前言 背乘法口诀表我没记错话&#xff0c;应该是我们在上小学二年级的时候&#xff0c;相信大家对乘法表相当熟悉&#xff0c;那你知道如何用java打印这个漂亮的表吗&#xff1f;下面咱们一起来学习学习。 具体代码 数字乘法表 关键代码&#xf…

ffmpeg视频滤镜:腐蚀滤镜

滤镜简述 erosion 官网链接> FFmpeg Filters Documentation 这个滤镜会在视频上应用腐蚀操作&#xff0c;腐蚀操作是形态学中一种操作&#xff0c;接触过opencv的同学应该很熟悉。滤镜主要有如下作用&#xff1a; 去除噪声&#xff1a;腐蚀可以帮助去除图像中的小颗粒噪…