tcp特点+TCP的状态转换图+time_wait详解

news2025/4/21 20:27:26

tcp特点+TCP的状态转换图+time wait详解

目录

一、tcp特点解释

1.1 面向连接

1.1.1 连接建立——三次握手

1.1.2 连接释放——四次挥手

1.2 可靠的

1.2.1 应答确认

1.2.2 超时重传

1.2.3 乱序重排

1.2.4 去重

1.2.5 滑动窗口进行流量控制

1.3 流失服务(字节流传输)

1.3.1 tcp粘包概念

1.3.2 产生 TCP 粘包的原因

发送端原因

接收端原因

1.3.3 解决 TCP 粘包的方法

定长协议

分隔符协议

消息头 + 消息体协议

二、服务器接收多个客户端 

三、TCP(传输控制协议)的状态转换图

2.1 状态

2.2 转换


一、tcp特点解释

1.1 面向连接

1.1.1 连接建立——三次握手

在进行数据传输之前,TCP 需要通过 “三次握手” 来建立连接。具体过程为:客户端向服务器发送一个 SYN 包,请求建立连接;服务器收到 SYN 包后,向客户端发送一个 SYN + ACK 包,表示同意建立连接;客户端收到 SYN + ACK 包后,再向服务器发送一个 ACK 包,连接建立完成。这种方式确保了双方都有发送和接收数据的能力,并且双方对连接的初始序列号达成一致。

1.1.2 连接释放——四次挥手

数据传输结束后,TCP 使用 “四次挥手” 来释放连接。客户端发送一个 FIN 包,表示请求关闭连接;服务器收到 FIN 包后,发送一个 ACK 包表示同意关闭;接着服务器发送一个 FIN 包,表示自己也请求关闭连接;客户端收到 FIN 包后,发送一个 ACK 包表示同意关闭,连接释放完成。这种机制保证了双方都能正确地结束数据传输。

1.2 可靠的

1.2.1 应答确认

TCP 使用确认机制来确保数据的可靠传输。发送方发送数据后,会等待接收方的确认信息(ACK)。如果在一定时间内没有收到确认信息,发送方会重新发送该数据。例如,发送方发送了一个数据包,接收方收到后会返回一个带有确认号的 ACK 包,告知发送方已经正确接收了哪些数据。

1.2.2 超时重传

当发送方发送的数据丢失或者接收方返回的确认信息丢失时,发送方会在超时后重传数据。TCP 通过设置定时器来实现超时重传,定时器的时间会根据网络状况动态调整。

1.2.3 乱序重排

我们每发一个tcp报文都有相应的序号。TCP 保证字节流中的数据按照发送的顺序到达接收方。如果数据在传输过程中出现乱序,TCP 会在接收方进行重新排序,确保应用层接收到的数据是有序的

1.2.4 去重

俩个相同序号的报文去重

1.2.5 滑动窗口进行流量控制

滑动窗口用于控制数据的发送速率和流量,同时保证数据的可靠传输。发送方和接收方都有一个滑动窗口,窗口的大小表示可以发送或接收的数据量。滑动窗口越大代表我能发送的数据越大.发送方在发送数据时,会根据接收方的窗口大小来决定发送多少数据,避免接收方缓冲区溢出。窗口内的允许发送,窗口外的不允许发送

(不会丢包因为是可靠的,底层可能会丢但是会重传时间特别快,我们应用层感受不到)

1.3 流失服务(字节流传输)

多线程并发——给一个服务器同时链接俩个以上客户端

发送缓冲区:send数据写到这里

接收缓冲区:recv接收数据

TCP 将应用层的数据看作是无边界的字节流进行传输。发送方可以将多个应用层的消息合并成一个字节流发送,接收方需要自己从字节流中提取出各个消息。例如,应用层发送了两条消息 “Hello” 和 “World”,TCP 可能会将它们合并成一个字节流 “HelloWorld” 进行发送,接收方需要根据具体的协议来区分这两条消息。

1.3.1 tcp粘包概念

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。而 TCP 粘包是在使用 TCP 进行数据传输时可能遇到的一个常见问题。

TCP 粘包指的是在 TCP 连接中,发送方发送的若干个数据包,到接收方接收时,这些数据包粘连在一起,接收方难以区分哪些字节属于哪个原始数据包的现象。 

1.3.2 产生 TCP 粘包的原因

发送端原因
  • Nagle 算法:TCP 为了提高传输效率,采用了 Nagle 算法。该算法会将小的数据包合并成大的数据包进行发送,以此减少网络中的数据包数量。例如,当你连续发送多个小数据包时,Nagle 算法可能会将它们合并成一个大的数据包发送,从而造成粘包。
  • TCP 缓冲区:TCP 协议的发送缓冲区用于暂存待发送的数据。如果发送方的数据产生速度大于网络的发送速度,那么数据就会在缓冲区中累积,当缓冲区满或者达到一定条件时,就会将缓冲区中的数据一起发送出去,这也可能导致多个数据包粘连在一起。
接收端原因
  • TCP 接收缓冲区:接收端在接收数据时,会将数据先存放在接收缓冲区中。如果接收方没有及时从缓冲区中读取数据,后续的数据也会不断地存入缓冲区,这样就可能导致多个数据包的数据混合在一起,形成粘包。

1.3.3 解决 TCP 粘包的方法

定长协议

规定每个数据包的长度是固定的。接收方按照固定长度来读取数据,这样就可以明确区分每个数据包。

分隔符协议

在每个数据包的末尾添加一个特殊的分隔符,接收方根据分隔符来区分不同的数据包。

消息头 + 消息体协议

在每个数据包的前面添加一个消息头,消息头中包含消息体的长度信息。接收方先读取消息头,根据消息头中的长度信息来读取相应长度的消息体。

二、服务器接收多个客户端 用fork做并发

它是一个简单的TCP服务器程序,它在本地6000端口上监听连接请求,接受客户端的连接,并为每个连接创建一个新的进程来处理

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);//创建监听套接字
    if( -1 == sockfd )
    {
        exit(1);
    }

    //定义套接字地址结构, ipv4,ipv5,unix
    struct sockaddr_in saddr,caddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    //将套接字绑定到指定的IP地址和端口。如果绑定失败(返回-1),则打印错误信息并退出程序。
    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//指定ip port
    if( -1 == res)
    {
        printf("bind err\n");
        exit(1);
    }


    //使套接字进入监听状态,监听队列大小设置为5。如果监听失败(返回-1),则退出程序。
    res = listen(sockfd,5);//设置监听队列 大小是5
    if( -1 == res)
    {
        exit(1);
    }


    //进入一个无限循环,等待客户端的连接请求。accept函数用于接受连接请求,并将客户端的地址信息存储在caddr中。
    while( 1 )
    {
        int len = sizeof(caddr);
        int c = accept(sockfd,(struct sockaddr*)&caddr,&len);

    //检查是否成功接受连接。如果失败,则继续下一次循环。
        if( c < 0 )
        {
            continue;
        }


    //创建一个新的进程来处理这个连接。如果创建进程失败,则关闭连接并继续下一次循环
        pid_t pid = fork();
        if( pid == -1 )
        {
            close(c);
            continue;
        }


    //在子进程中,进入一个无限循环,接收客户端发送的数据,并发送"ok"作为响应。如果接收失败或客户端关闭连接,则打印信息,关闭连接,并退出子进程。
        if( pid == 0 )
        {
            while( 1 )
            {
                char buff[128] = {0};

                int n = recv(c,buff,127,0);
                if( n<= 0 )
                {
                    break;
                }

                printf("recv:%s\n",buff);
                send(c,"ok",2,0);
            }
            printf("client close\n");
            close(c);
            exit(0);
        }

        close(c);

    }
}

这个程序实现了一个简单的TCP服务器,它可以在本地6000端口上监听连接请求,接受客户端的连接,并为每个连接创建一个新的进程来处理。服务器接收客户端发送的数据,并发送"ok"作为响应。服务器使用多进程模型来处理多个客户端的连接。 

TCP客户端程序cli,它连接到本地服务器(127.0.0.1),发送消息,并接收服务器的响应

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main()
{
    //创建一个TCP套接字。AF_INET 表示使用IPv4地址,SOCK_STREAM 表示使用面向连接的流式套接字。
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    //检查套接字是否创建成功。如果失败(返回-1),则退出程序。
    if( sockfd == -1 )
    {
        exit(1);
    }
    
    //定义并初始化服务器的地址结构。memset 用于清零结构体,sin_family 设置为IPv4,sin_port 设置为6000端口(使用htons函数转换为网络字节序),sin_addr.s_addr 设置为本地地址127.0.0.1(使用inet_addr函数转换为网络字节序)。
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("127.0.0.1");


    //尝试连接到服务器。如果连接失败(返回-1),则打印错误信息并退出程序。
    int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if ( res == -1 )
    {
        printf("connect err\n");
        exit(1);
    }


    //进入一个无限循环,提示用户输入,然后使用fgets函数从标准输入读取一行文本(最多127个字符),存储在缓冲区buff中。
    while( 1 )
    {
        printf("input\n");
        char buff[128] = {0};
        fgets(buff,128,stdin);


    //检查用户输入是否为"end"。如果是,则退出循环。
        if( strncmp(buff,"end",3) == 0 )
        {
            break;
        }


    //发送用户输入的消息到服务器(不包括换行符),清空缓冲区,接收服务器的响应,并打印出来。
        send(sockfd,buff,strlen(buff)-1,0);
        memset(buff,0,128);
        recv(sockfd,buff,127,0);
        printf("read:%s\n",buff);
    }

    close(sockfd);

    exit(0);
}

 这个程序实现了一个简单的TCP客户端,可以连接到本地服务器,发送消息,并接收服务器的响应。它使用了基本的套接字编程技术,包括创建套接字、连接服务器、发送和接收数据以及关闭套接字。程序通过一个无限循环来持续接收用户输入,并在输入"end"时退出。

 

这两段代码分别实现了一个简单的 TCP 客户端和一个 TCP 服务器。

 TCP 服务器代码解释

这段代码实现了一个 TCP 服务器,它在本地计算机的 6000 端口上监听来自客户端的连接请求。

1. **创建套接字**:
   - 使用 `socket` 函数创建一个 TCP 套接字 `sockfd`。

2. **绑定地址**:
   - 使用 `bind` 函数将套接字绑定到本地地址 `127.0.0.1` 和端口 `6000` 上。这样,服务器就准备好在指定的地址和端口上监听客户端的连接请求。

3. **监听连接**:
   - 使用 `listen` 函数使套接字进入监听状态,等待客户端的连接请求。监听队列的大小设置为 5,这意味着服务器可以同时处理最多 5 个未处理的连接请求。

4. **接受连接**:
   - 使用 `accept` 函数接受客户端的连接请求。每当有新的客户端连接时,`accept` 函数会返回一个新的套接字 `c`,用于与该客户端进行通信。

5. **处理客户端请求**:
   - 使用 `fork` 创建一个新的子进程来处理每个客户端的请求。这样,服务器可以同时处理多个客户端的连接。
   - 在子进程中,使用 `recv` 函数接收客户端发送的数据,并使用 `send` 函数发送响应(在这个例子中,响应是字符串 "ok")。
   - 当客户端关闭连接或发生错误时,子进程会退出。

6. **关闭连接**:
   - 在父进程中,关闭与客户端的连接套接字 `c`。

 TCP 客户端代码解释

这段代码实现了一个 TCP 客户端,它连接到本地服务器(127.0.0.1:6000),发送消息,并接收服务器的响应。

1. **创建套接字**:
   - 使用 `socket` 函数创建一个 TCP 套接字 `sockfd`。

2. **连接到服务器**:
   - 使用 `connect` 函数连接到服务器的地址 `127.0.0.1` 和端口 `6000` 上。

3. **发送和接收数据**:
   - 进入一个无限循环,提示用户输入消息。
   - 使用 `fgets` 函数从标准输入读取用户输入的消息。
   - 如果用户输入 "end",则退出循环,关闭连接并退出程序。
   - 使用 `send` 函数将用户输入的消息发送到服务器。
   - 使用 `recv` 函数接收服务器的响应,并使用 `printf` 函数打印响应。

4. **关闭连接**:
   - 在退出循环后,关闭与服务器的连接套接字 `sockfd`。

### 总结

这两段代码实现了一个简单的 TCP 客户端-服务器通信模型:

- **服务器**:在本地计算机的 6000 端口上监听客户端的连接请求,使用多进程模型来处理每个客户端的请求。服务器接收客户端发送的数据,并发送 "ok" 作为响应。
- **客户端**:连接到本地服务器,发送用户输入的消息,并接收服务器的响应。

这种模型可以用于实现各种基于 TCP 的网络应用程序,如聊天程序、文件传输等。

会出现僵死进程,所以需要加入信号的使用来解决僵死进程

三、TCP(传输控制协议)的状态转换图

展示了TCP连接从建立到关闭的整个过程中可能经历的各种状态。

2.1 状态

1. **CLOSED**:初始状态,表示连接尚未建立。
2. **LISTEN**:服务器在该状态监听来自客户端的连接请求。
3. **SYN_SENT**:客户端发送SYN请求连接,等待服务器确认。
4. **SYN_RCVD**:服务器收到SYN请求后,发送SYN+ACK响应,进入此状态,等待客户端的确认。
5. **ESTABLISHED**:双方确认连接后,连接建立,可以开始传输数据。
6. **FIN_WAIT_1**:主动关闭连接的一方发送FIN请求,希望关闭连接。
7. **FIN_WAIT_2**:在FIN_WAIT_1状态下收到对方的ACK后,进入此状态,等待对方的FIN请求。
8. **CLOSING**:双方同时发送FIN请求,等待对方的ACK。
9. **TIME_WAIT**:主动关闭连接的一方在发送FIN请求并收到对方的ACK后,进入此状态,等待一段时间以确保对方收到ACK。
10. **CLOSE_WAIT**:被动关闭连接的一方收到FIN请求后,进入此状态,等待应用程序关闭连接。
11. **LAST_ACK**:被动关闭连接的一方发送FIN请求后,等待对方的ACK。

2.2 转换

1. **被动打开**:服务器从CLOSED状态进入LISTEN状态,等待客户端的连接请求。
2. **主动打开**:客户端从CLOSED状态发送SYN请求,进入SYN_SENT状态。
3. **连接建立**:
   - 客户端发送SYN请求,进入SYN_SENT状态。
   - 服务器收到SYN请求,发送SYN+ACK响应,进入SYN_RCVD状态。
   - 客户端收到SYN+ACK响应,发送ACK确认,进入ESTABLISHED状态。
   - 服务器收到ACK确认,进入ESTABLISHED状态。
4. **数据传输**:在ESTABLISHED状态下,双方可以进行数据传输。
5. **连接关闭**:
   - 主动关闭的一方发送FIN请求,进入FIN_WAIT_1状态。
   - 被动关闭的一方收到FIN请求,发送ACK确认,进入CLOSE_WAIT状态。
   - 被动关闭的一方发送FIN请求,进入LAST_ACK状态。
   - 主动关闭的一方收到FIN请求,发送ACK确认,进入TIME_WAIT状态。
   - TIME_WAIT状态持续一段时间后,连接关闭,进入CLOSED状态。 

TCP连接的建立和关闭是一个复杂的过程,涉及到多个状态和状态转换。连接建立需要三次握手(SYN, SYN+ACK, ACK),而连接关闭需要四次挥手(FIN, ACK, FIN, ACK)。这种设计确保了连接的可靠性和数据的完整性。

在Linux系统中使用netstat命令查看网络连接状态的输出结果。netstat是一个常用的网络工具,用于显示网络连接、路由表、接口统计等信息。图片中的命令netstat -nat用于显示所有网络连接和监听端口,包括TCP和UDP协议,并且不解析服务名称

  1. 输出字段

    • Proto:协议类型,如TCP或TCP6。

    • Recv-Q:接收队列长度。

    • Send-Q:发送队列长度。

    • Local Address:本地地址和端口。

    • Foreign Address:远程地址和端口。

    • State:连接状态,如LISTEN、ESTABLISHED、CLOSE_WAIT等。

    • PID/Program name:进程ID和程序名称。

  2. 状态解释

    • LISTEN:端口正在监听,等待连接请求。

    • ESTABLISHED:连接已建立,数据可以传输。

    • CLOSE_WAIT:被动关闭连接的一方等待关闭连接。

    • FIN_WAIT_1:主动关闭连接的一方等待对方的FIN请求。

    • FIN_WAIT_2:主动关闭连接的一方等待对方的ACK确认。

    • TIME_WAIT:主动关闭连接的一方等待一段时间以确保对方收到ACK。

  • 第一张图显示了多个端口处于LISTEN状态,表示这些端口正在等待连接请求。

  • 第二张图显示了一个端口(127.0.0.1:6000)已经完成了三次握手,处于ESTABLISHED状态,表示连接已经建立。

  • 第三张图显示了一个端口(127.0.0.1:6000)处于CLOSE_WAIT状态,表示被动关闭连接的一方等待关闭连接。

变成time wait端口被占用 状态服务器不能启动

为什么需要time wait状态? 

1. 可靠的终止TCP连接

TCP 连接的终止需要通过四次挥手过程来完成。在主动关闭连接的一方发送了 FIN 报文后,它需要等待对方的 ACK 报文。然而,由于网络延迟或其他原因,这个 ACK 报文可能会丢失或延迟到达。如果主动关闭方在发送 FIN 报文后立即关闭,那么它将无法接收到这个 ACK 报文,从而导致连接没有被正确关闭。

为了避免这种情况,主动关闭方会进入 TIME_WAIT 状态,等待一段时间(通常是 2 倍的 MSL,即 Maximum Segment Lifetime,报文段的最大生存时间)。这段时间足够长,可以确保即使 ACK 报文丢失或延迟,主动关闭方也能够接收到来自对方的重传 ACK 报文,从而可靠地终止连接。

2. 保证让迟来的TCP报文段有足够的时间被识别并丢弃

TCP 连接的标识是由源 IP 地址、目的 IP 地址、源端口号和目的端口号共同组成的。当一个 TCP 连接被关闭后,这些标识可能会被新的连接所使用。然而,由于网络延迟或其他原因,旧连接的报文段可能会在连接关闭后仍然存在于网络中。

如果新的连接使用了相同的标识,那么这些迟来的旧报文段可能会被错误地识别为新连接的报文段,从而导致数据混乱。TIME_WAIT 状态通过等待一段时间,确保所有旧的报文段都已经被丢弃或过期,从而避免这种情况的发生。

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

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

相关文章

高支模自动化监测解决方案

1.行业现状 高大模板支撑系统在浇筑施工过程中&#xff0c;诸多重大安全风险点进行实时自动化安全监测的解决方案主要监测由于顶杆失稳、扣件失效、承压过大等引起的支撑轴力、模板沉降、相对位移、支撑体系倾斜等参数变化。系统采用无线自动组网、高频连续采样&#xff0c;实时…

OpenCV 图形API(24)图像滤波-----双边滤波函数bilateralFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 应用双边滤波到图像。 该函数对输入图像应用双边滤波&#xff0c;如 http://www.dai.ed.ac.uk/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Fil…

HarmonyOS中的多线程并发机制

目录 多线程并发1. 多线程并发概述2 多线程并发模型3 TaskPool简介4 Worker简介4.1 Woker注意事项4.2 Woker基本用法示例 5. TaskPool和Worker的对比5.1 实现特点对比5.2 适用场景对比 多线程并发 1. 多线程并发概述 并发模型是用来实现不同应用场景中并发任务的编程模型&…

【随手笔记】QT避坑一(串口readyRead信号不产生)

问题描述&#xff1a; 使用QT5.15.2版本 测试串口readyRead绑定槽函数&#xff0c;接收到数据后 不能触发 试了很多网友的程序&#xff0c;他们的发布版本可以&#xff0c;但是源码我编译后就不能触发&#xff0c;判断不是代码的问题 看到有人提到QT版本的问题&#xff0c;于…

【产品】ToB产品需求分析

需求分析流程 合格产品经理 帮助用户、引导用户、分析需求、判断需求、设计方案 不能苛求用户提出合理、严谨的需求&#xff0c;这不是用户的责任和义务&#xff0c;而应该通过自己的专业能力来完成需求的采集工作 #mermaid-svg-ASu8vocank48X6FI {font-family:"trebuche…

驱动开发硬核特训 · Day 10 (理论上篇):设备模型 ≈ 运行时的适配器机制

&#x1f50d; B站相应的视屏教程&#xff1a; &#x1f4cc; 内核&#xff1a;博文视频 - 总线驱动模型实战全解析 敬请关注&#xff0c;记得标为原始粉丝。 在 Linux 驱动开发中&#xff0c;设备模型&#xff08;Device Model&#xff09;是理解驱动架构的核心。而从软件工程…

flutter 打包mac程序 dmg教程

✅ 前提条件 ✅ 你已经在 macOS 上安装了 Android Studio Flutter SDK。 ✅ Flutter 支持 macOS 构建。 运行下面命令确认是否支持&#xff1a; Plain Text bash 复制编辑 flutter doctor ---## &#x1f9f1; 第一步&#xff1a;启用 macOS 支持如果是新项目&#xff0c;…

【数据结构与算法】——堆(补充)

前言 上一篇文章讲解了堆的概念和堆排序&#xff0c;本文是对堆的内容补充 主要包括&#xff1a;堆排序的时间复杂度、TOP 这里写目录标题 前言正文堆排序的时间复杂度TOP-K 正文 堆排序的时间复杂度 前文提到&#xff0c;利用堆的思想完成的堆排序的代码如下&#xff08;包…

atypica.AI:用「语言模型」为「主观世界」建模

人们不是在处理概率&#xff0c;而是在处理故事。 —— 丹尼尔卡尼曼 People dont choose between things, they choose between descriptions of things. —— Daniel Kahneman 商业研究是一门理解人类决策的学问。人并不只是根据纯粹理性做决策&#xff0c;而是受到叙事、情…

LLaMA-Factory双卡4090微调DeepSeek-R1-Distill-Qwen-14B医学领域

unsloth单卡4090微调DeepSeek-R1-Distill-Qwen-14B医学领域后&#xff0c;跑通一下多卡微调。 1&#xff0c;准备2卡RTX 4090 2&#xff0c;准备数据集 医学领域 pip install -U huggingface_hub export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download --resum…

【WPF】自定义控件:ShellEditControl-同列单元格编辑支持文本框、下拉框和弹窗

需要实现表格同一列&#xff0c;单元格可以使用文本框直接输入编辑、下拉框选择和弹窗&#xff0c;文本框只能输入数字&#xff0c;弹窗中的数据是若干位的二进制值。 本文提供了两种实现单元格编辑状态下&#xff0c;不同编辑控件的方法&#xff1a; 1、DataTrigger控制控件的…

Seq2Seq - GRU补充讲解

nn.GRU 是 PyTorch 中实现门控循环单元&#xff08;Gated Recurrent Unit, GRU&#xff09;的模块。GRU 是一种循环神经网络&#xff08;RNN&#xff09;的变体&#xff0c;用于处理序列数据&#xff0c;能够更好地捕捉长距离依赖关系。 ⭐重点掌握输入输出部分输入张量&#…

从零开始学Python游戏编程19-游戏循环模式1

在《从零开始学Python游戏编程18-函数3》中提到&#xff0c;可以对游戏代码进行重构&#xff0c;把某些代码写入函数中&#xff0c;主程序再调用这些函数&#xff0c;这样使得代码程序更容易理解和维护。游戏循环模式实际上也是把代码写入到若干个函数中&#xff0c;通过循环的…

Java获取终端设备信息工具类

在很多场景中需要获取到终端设备的一些硬件信息等&#xff0c;获取的字段如下&#xff1a; 返回参数 参数含义备注systemName系统名称remoteIp公网iplocalIp本地ip取IPV4macmac地址去掉地址中的"-“或”:"进行记录cpuSerialcpu序列号hardSerial硬盘序列号drive盘符…

【Linux网络与网络编程】08.传输层协议 UDP

传输层协议负责将数据从发送端传输到接收端。 一、再谈端口号 端口号标识了一个主机上进行通信的不同的应用程序。在 TCP/IP 协议中&#xff0c;用 "源IP"&#xff0c;"源端口号"&#xff0c;"目的 IP"&#xff0c;"目的端口号"&…

没音响没耳机,把台式电脑声音播放到手机上

第一步&#xff0c;电脑端下载安装e2eSoft VSC虚拟声卡&#xff08;安装完成后关闭&#xff0c;不要点击和设置&#xff09; 第二步&#xff0c;电脑端下载安装&#xff08;SoundWire Server&#xff09;&#xff08;安装完成后不要关闭&#xff0c;保持默认配置&#xff09; 第…

XDocument和XmlDocument的区别及用法

因为这几天用到了不熟悉的xml统计数据&#xff0c;啃了网上的资料解决了问题&#xff0c;故总结下xml知识。 1.什么是XML?2.XDocument和XmlDocument的区别3.XDocument示例1示例2&#xff1a;示例3&#xff1a; 4.XmlDocument5.LINQ to XML6.XML序列化(Serialize)与反序列化(De…

Blender安装基础使用教程

本博客记录安装Blender和基础使用&#xff0c;可以按如下操作来绘制标靶场景、道路标识牌等。 目录 1.安装Blender 2.创建面板资源 步骤 1: 设置 Blender 场景 步骤 2: 创建一个平面 步骤 3: 将 PDF 转换为图像 步骤 4-方法1: 添加材质并贴图 步骤4-方法2&#xff1a;创…

【Git】从零开始使用git --- git 的基本使用

哪怕是野火焚烧&#xff0c;哪怕是冰霜覆盖&#xff0c; 依然是志向不改&#xff0c;依然是信念不衰。 --- 《悟空传》--- 从零开始使用git 了解 Gitgit创建本地仓库初步理解git结构版本回退 了解 Git 开发场景中&#xff0c;文档可能会经历若干版本的迭代。假如我们不进行…

Android 中支持旧版 API 的方法(API 30)

Android 中最新依赖库的版本支持 API 31 及以上版本&#xff0c;若要支持 API30&#xff0c;则对应的依赖库的版本就需要使用旧版本。 可通过修改模块级 build.gradle 文件来进行适配。 1、android 标签的 targetSdk 和 compileSdk 版本号 根据实际目标设备的 android 版本来…