使用套接字创建一个服务端,创建一个客户端然后相互通讯

news2025/1/2 12:53:11

在这里插入图片描述
在这里插入图片描述
以下是对上述代码的详细解释:

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


// 定义 sockaddr 结构体类型别名 sa_t
typedef  struct sockaddr       sa_t;
// 定义 sockaddr_in 结构体类型别名 sin_t
typedef  struct sockaddr_in    sin_t;


int main(int argc, char** argv)
{
    // 检查命令行参数是否足够
    if (argc < 3)
    {
        // 输出使用说明,如果命令行参数不足,程序无法正常运行
        fprintf(stderr, "Usage <%s servIP servPort>\n", argv[0]);
        return -1;
    }


    // 1. 创建数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        // 如果套接字创建失败,输出错误信息并退出程序
        perror("socket");
        exit(-1);
    }


    // 2. 绑定服务器端地址信息到套接字上
    sin_t               server = {AF_INET};
    // 将服务器端口号转换为网络字节序
    server.sin_port            = htons( atoi(argv[2]));
    // 将服务器 IP 地址从点分十进制转换为网络字节序
    server.sin_addr.s_addr     = inet_addr(argv[1]);
    int  len  = sizeof(sin_t);
    if (-1 == bind(sockfd, (sa_t*)&server, len))
    {
        // 如果绑定失败,输出错误信息,关闭套接字并退出程序
        perror("bind");
        close(sockfd);
        exit(-1);
    }


    while (1)
    {    
        // 3. 接收客户端发来的网络数据
        char buf[64] = {0};
        sin_t   peer = {0};
        int n  = recvfrom(sockfd, buf, sizeof(buf)-1, 0, (sa_t*)&peer, &len);
        // 在接收的数据末尾添加字符串结束符
        buf[n] = '\0';
        // 打印客户端的 IP 地址、端口号和发送的数据
        printf("[%s:%d]发来数据:%s\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port), buf);


        // 4. 回复数据给客户端
        const char* resp[] = {"继续努力", "百尺杆头", "百舸争流", "干的漂亮"};
        int sz = sizeof resp / sizeof resp[0];
        // 随机选择一个回复信息
        int  i = rand() % sz;
        // 向客户端发送回复信息
        sendto(sockfd, resp[i], strlen(resp[i]), 0, (sa_t*)&peer, len);
    }


    // 关闭套接字
    close(sockfd);
    return 0;
}

代码解释

  1. 头文件部分

    • <unistd.h>:提供了通用的文件、目录、进程等操作的接口,这里可能用于 close 函数。
    • <sys/types.h>:包含了基本的系统数据类型。
    • <sys/socket.h>:包含了套接字相关的函数和结构体的声明,如 socketbindrecvfromsendto 等。
    • <netinet/in.h>:包含了 struct sockaddr_in 结构体,用于存储 IPv4 地址信息。
    • <arpa/inet.h>:包含了 inet_addrinet_ntoa 等网络地址转换函数。
    • <stdio.h>:用于输入输出操作,如 printffprintf
    • <stdlib.h>:提供了一些标准的库函数,如 exit
    • <string.h>:提供了字符串操作函数,如 strlen
  2. 类型别名部分

    • typedef struct sockaddr sa_t;:将 struct sockaddr 结构体类型定义为 sa_t,方便后续使用。
    • typedef struct sockaddr_in sin_t;:将 struct sockaddr_in 结构体类型定义为 sin_t,方便后续使用。
  3. 主函数部分

    • 参数检查
      • if (argc < 3):检查命令行参数数量,如果小于 3 个,输出使用说明并返回 -1。程序需要两个参数,即服务器的 IP 地址和端口号。
    • 套接字创建
      • int sockfd = socket(AF_INET, SOCK_DGRAM, 0);:创建一个 UDP 套接字。AF_INET 表示使用 IPv4 地址族,SOCK_DGRAM 表示使用数据报(UDP)协议,0 表示使用默认的协议。
      • if (sockfd == -1):检查套接字创建是否失败,如果失败使用 perror 输出错误信息并退出程序。
    • 地址绑定
      • sin_t server = {AF_INET};:创建并初始化 sin_t 结构体,将地址族设置为 AF_INET
      • server.sin_port = htons(atoi(argv[2]));:将服务器端口号从主机字节序转换为网络字节序。
      • server.sin_addr.s_addr = inet_addr(argv[1]);:将服务器 IP 地址从点分十进制表示转换为网络字节序。
      • int len = sizeof(sin_t);:计算 sin_t 结构体的长度。
      • if (-1 == bind(sockfd, (sa_t*)&server, len)):将服务器地址绑定到套接字上,如果绑定失败,输出错误信息,关闭套接字并退出程序。
    • 数据接收和回复循环
      • while (1):程序进入一个无限循环,持续处理客户端请求。
      • char buf[64] = {0};:创建一个 64 字节的接收缓冲区,并初始化为 0。
      • sin_t peer = {0};:创建一个 sin_t 结构体来存储客户端的地址信息。
      • int n = recvfrom(sockfd, buf, sizeof(buf)-1, 0, (sa_t*)&peer, &len);:从套接字接收数据,存储在 buf 中,sizeof(buf)-1 为接收数据的最大长度,0 表示无特殊标志,(sa_t*)&peer 存储发送者的地址,&len 存储地址长度。
      • buf[n] = '\0';:在接收的数据末尾添加字符串结束符。
      • printf("[%s:%d]发来数据:%s\n", inet_ntoa(peer.sin_addr), ntohs(peer.sin_port), buf);:打印客户端的 IP 地址、端口号和发送的数据。
      • const char* resp[] = {"继续努力", "百尺杆头", "百舸争流", "干的漂亮"};:定义一个回复信息数组。
      • int sz = sizeof resp / sizeof resp[0];:计算回复信息数组的元素个数。
      • int i = rand() % sz;:随机选择一个回复信息的索引。
      • sendto(sockfd, resp[i], strlen(resp[i]), 0, (sa_t*)&peer, len);:向客户端发送回复信息,包括选择的回复信息、信息长度、无特殊标志、客户端地址和地址长度。
  4. 套接字关闭

    • close(sockfd);:关闭套接字,释放资源。

注意事项

  • 此代码实现了一个简单的 UDP 服务器,可接收客户端发送的数据并随机回复一条信息。
  • 代码没有处理 recvfromsendto 可能出现的错误情况,可使用 perror 或其他方式处理错误。
  • 代码使用了 rand() 函数但没有调用 srand() 函数设置随机数种子,每次运行可能产生相同的随机数序列,可在 main 函数开始处调用 srand(time(NULL)); 解决。
  • 代码没有处理可能出现的缓冲区溢出问题,如客户端发送的数据超过 63 字节,会导致数据截断。
客户端完整代码
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef  struct sockaddr       sa_t;
typedef  struct sockaddr_in    sin_t;


int main(int argc,char** argv)
{
    if(argc < 3)
    {
         fprintf(stderr,"Usage <%s servIP servPort>\n",argv[0]);
         return -1;
    }
    /*1 创建数据报套接字*/
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd == -1)
    {
         perror("socket");
         exit(-1);
    }
    /*2 绑定服务器端地址信息到套接字上*/
    sin_t               server = {AF_INET};
    server.sin_port            = htons( atoi(argv[2]));
    server.sin_addr.s_addr     = inet_addr(argv[1]);
    int  len  = sizeof(sin_t);
    if(-1 == bind(sockfd,(sa_t*)&server,len))
    {
         perror("bind");
         close(sockfd);
         exit(-1);
    }
    while(1)
    {    
      /*3接收客户端发来的网络数据*/
      char buf[64] = {0};
      sin_t   peer = {0};
      int n  = recvfrom(sockfd,buf,sizeof(buf)-1,0,(sa_t*)&peer,&len);
      buf[n] = '\0';
      printf("[%s:%d]发来数据:%s\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port),buf);
      
      /*4.回复数据给客户端*/
      const char* resp[] = {"继续努力","百尺杆头","百舸争流","干的漂亮"};
      int sz = sizeof resp / sizeof resp[0];
      int  i = rand() % sz;
      sendto(sockfd,resp[i],strlen(resp[i]),0,(sa_t*)&peer,len);
    }
    close(sockfd);
    return 0;
}

在这里插入图片描述
客户端代码
以下是对这段代码的详细解释:

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


typedef  struct sockaddr       sa_t;
typedef  struct sockaddr_in    sin_t;


int main(int argc, char** argv)
{
    // 检查命令行参数是否足够
    if (argc < 3)
    {
        // 输出使用说明,如果命令行参数不足,程序无法正常运行
        fprintf(stderr, "Usage <%s servIP servPort>\n", argv[0]);
        return -1;
    }


    // 定义缓冲区大小
    #define BUFFER_SIZE 1024


    // 1. 创建数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        // 如果套接字创建失败,输出错误信息并退出程序
        perror("socket");
        exit(-1);
    }


    // 声明和初始化 server_address
    sin_t server_address = {0};
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(atoi(argv[2]));
    if (inet_pton(AF_INET, argv[1], &server_address.sin_addr) <= 0) 
    {
        // 如果 IP 地址转换失败,输出错误信息并退出程序
        perror("inet_pton");
        exit(EXIT_FAILURE);
    }


    // 声明 client_socket
    int client_socket;


    // 连接到服务器
    client_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (client_socket == -1) 
    {
        // 如果套接字创建失败,输出错误信息并退出程序
        perror("socket");
        exit(EXIT_FAILURE);
    }


    if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) 
    {
        // 如果连接失败,输出错误信息并退出程序
        perror("connect");
        exit(EXIT_FAILURE);
    }


    // 正确声明和初始化 len
    socklen_t len = sizeof(sin_t);


    while (1)
    {
        // 声明并初始化要发送的字符串
        char *hello = "席甜千到此一游";


        // 发送消息给服务端
        send(client_socket, hello, strlen(hello), 0);
        printf("Message sent to server: %s\n", hello);


        // 声明接收数据的缓冲区
        char buffer[BUFFER_SIZE];


        // 接收服务端的信息
        int valread = recv(client_socket, buffer, BUFFER_SIZE, 0);
        if (valread == -1)
        {
            // 如果接收失败,输出错误信息并继续下一次循环
            perror("recv");
            continue;
        }
        buffer[valread] = '\0';
        printf("Message received from server: %s\n", buffer);


        // 错误:此处不应关闭 sockfd,因为后续可能还需要使用
        // close(sockfd); 
    }


    // 关闭客户端套接字
    close(client_socket);


    return 0;
}

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

代码解释

  1. 头文件部分

    • <stdio.h>:提供标准输入输出函数,如 printffprintf
    • <stdlib.h>:提供了一些标准的库函数,如 exit
    • <string.h>:提供了字符串操作函数,如 strlen
    • <sys/socket.h>:包含了套接字相关的函数和结构体的声明,如 socketconnectsendrecv 等。
    • <arpa/inet.h>:包含了 inet_pton 等网络地址转换函数。
    • <unistd.h>:提供了 close 等系统调用函数。
  2. 类型别名部分

    • typedef struct sockaddr sa_t;:将 struct sockaddr 结构体类型定义为 sa_t,方便后续使用。
    • typedef struct sockaddr_in sin_t;:将 struct sockaddr_in 结构体类型定义为 sin_t,方便后续使用。
  3. 主函数部分

    • 参数检查
      • if (argc < 3):检查命令行参数数量,如果小于 3 个,输出使用说明并返回 -1。程序需要两个参数,即服务器的 IP 地址和端口号。
    • 套接字创建
      • int sockfd = socket(AF_INET, SOCK_DGRAM, 0);:创建一个 UDP 套接字。AF_INET 表示使用 IPv4 地址族,SOCK_DGRAM 表示使用数据报(UDP)协议,0 表示使用默认的协议。
      • if (sockfd == -1):检查套接字创建是否失败,如果失败使用 perror 输出错误信息并退出程序。
    • 服务器地址初始化
      • sin_t server_address = {0};:创建并初始化 sin_t 结构体,将地址族设置为 AF_INET
      • server_address.sin_port = htons(atoi(argv[2]));:将服务器端口号从主机字节序转换为网络字节序。
      • if (inet_pton(AF_INET, argv[1], &server_address.sin_addr) <= 0):将服务器 IP 地址从点分十进制表示转换为网络字节序,如果转换失败,输出错误信息并退出程序。
    • 客户端套接字创建和连接
      • int client_socket;:声明一个客户端套接字变量。
      • client_socket = socket(AF_INET, SOCK_DGRAM, 0);:创建另一个 UDP 套接字作为客户端套接字。
      • if (client_socket == -1):检查套接字创建是否失败,如果失败使用 perror 输出错误信息并退出程序。
      • if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1):尝试将客户端套接字连接到服务器地址,如果连接失败,输出错误信息并退出程序。
    • 数据传输和接收循环
      • socklen_t len = sizeof(sin_t);:计算 sin_t 结构体的长度。
      • while (1):程序进入一个无限循环,持续发送和接收数据。
      • char *hello = "席甜千到此一游";:定义要发送的字符串。
      • send(client_socket, hello, strlen(hello), 0);:使用 send 函数将字符串发送给服务器。
      • printf("Message sent to server: %s\n", hello);:打印发送的消息。
      • char buffer[BUFFER_SIZE];:创建一个接收缓冲区。
      • int valread = recv(client_socket, buffer, BUFFER_SIZE, 0);:接收服务器发送的数据。
      • if (valread == -1):如果接收失败,输出错误信息并继续下一次循环。
      • buffer[valread] = '\0';:在接收的数据末尾添加字符串结束符。
      • printf("Message received from server: %s\n", buffer);:打印接收到的消息。
    • 套接字关闭
      • close(client_socket);:关闭客户端套接字。

问题和优化点

  • 代码中创建了两个 UDP 套接字 sockfdclient_socket,但 sockfd 似乎没有被使用,可以考虑删除 sockfd 的创建。
  • while 循环中错误地调用了 close(sockfd);,应该将其移除,因为 sockfd 未被使用且可能导致后续操作失败。
  • 代码没有处理 recv 函数返回 0 的情况,可能需要根据具体情况进行处理。
  • 可以使用 #define 定义一些常量,如服务器端口号和 IP 地址,增强代码的可维护性。
  • 可以添加更多的错误处理,如处理服务器不可达等情况。
在这里插入代码片
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>


typedef  struct sockaddr       sa_t;
typedef  struct sockaddr_in    sin_t;


int main(int argc, char** argv)
{
    if (argc < 3)
    {
        fprintf(stderr, "Usage <%s servIP servPort>\n", argv[0]);
        return -1;
    }


    // 定义缓冲区大小
    #define BUFFER_SIZE 1024


    // 1. 创建数据报套接字
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket");
        exit(-1);
    }


    // 声明和初始化 server_address
    sin_t server_address = {0};
    server_address.sin_family = AF_INET;
    server_address.sin_port = htons(atoi(argv[2]));
    if (inet_pton(AF_INET, argv[1], &server_address.sin_addr) <= 0) 
    {
        perror("inet_pton");
        exit(EXIT_FAILURE);
    }


    // 声明 client_socket
    int client_socket;


    // 连接到服务器
    client_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (client_socket == -1) 
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }


    if (connect(client_socket, (struct sockaddr*)&server_address, sizeof(server_address)) == -1) 
    {
        perror("connect");
        exit(EXIT_FAILURE);
    }


    // 正确声明和初始化 len
    socklen_t len = sizeof(sin_t);


    while (1)
    {
        // 声明并初始化要发送的字符串
        char *hello = "席甜千到此一游";


        // 发送消息给服务端
        send(client_socket, hello, strlen(hello), 0);
        printf("Message sent to server: %s\n", hello);


        // 声明接收数据的缓冲区
        char buffer[BUFFER_SIZE];


        // 接收服务端的信息
        int valread = recv(client_socket, buffer, BUFFER_SIZE, 0);
        if (valread == -1)
        {
            perror("recv");
            continue;
        }
        buffer[valread] = '\0';
        printf("Message received from server: %s\n", buffer);
		close(sockfd);
    }


 /*    close(sockfd); */
    close(client_socket);


    return 0;
}

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

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

相关文章

ES 磁盘使用率检查及处理方法

文章目录 1. 检查原因2. 检查方法3. 处理方法3.1 清理数据3.2 再次检查磁盘使用率 1. 检查原因 磁盘使用率在 85%以下&#xff0c;ES 可正常运行&#xff0c;达到 85%及以上会影响 PEIM 数据存储。 在 ES 磁盘分配分片控制策略中&#xff0c;为了保护数据节点的安全&#xff0…

[cg] android studio 无法调试cpp问题

折腾了好久&#xff0c;native cpp库无法调试问题&#xff0c;原因 下面的Deploy 需要选Apk from app bundle!! 另外就是指定Debug type为Dual&#xff0c;并在Symbol Directories 指定native cpp的so路径 UE项目调试&#xff1a; 使用Android Studio调试虚幻引擎Android项目…

Flutter中添加全局防护水印的实现

随着版权意识的加强&#xff0c;越来越多的应用开始在应用内部增加各种各样的水印信息&#xff0c;防止核心信息泄露&#xff0c;便于朔源。 效果如下&#xff1a; 在Flutter中增加全局水印的方式&#xff0c;目前有两种实现。 方案一&#xff0c;在native层添加一个遮罩层&a…

MQTT——客户端安装使用(图文详解)

目录 一. 下载安装MQTT 1. 下载MQTT 2. 安装MQTT 二. MQTT客户端使用 1. 连接MQTT服务 2. MQTT发布消息 3. MQTT 消息订阅 4. 断开MQTT服务器连接 三. 使用Jmeter给MQTT发数据 一. 下载安装MQTT 1. 下载MQTT &#xff08;1&#xff09;官网下载地址&#xff1a;MQTTX…

2- 位段式结构体

文章目录 1 结构体内存对齐2 位段式结构体2.1 格式2.2 成员类型2.3 空间开辟2.4 示例2.4.1 示例12.4.2 示例2 1 结构体内存对齐 首成员对齐规则 结构体的第一个成员从偏移量为0的地址处开始存放&#xff0c;即与结构体的首地址对齐。 其他成员对齐规则 其他成员变量的存放地址…

Milvus×EasyAi:如何用java从零搭建人脸识别应用

如何从零搭建一个人脸识别应用&#xff1f;不妨试试原生Java人工智能算法&#xff1a;EasyAi Milvus 的组合拳。 本文将使用到的软件和工具包括&#xff1a; EasyAi&#xff1a;人脸特征向量提取Milvus&#xff1a;向量数据库用于高效存储和检索数据。 01. EasyAi&#xff1a;…

AWS K8s 部署架构

Amazon Web Services&#xff08;AWS&#xff09;提供了一种简化的Kubernetes&#xff08;K8s&#xff09;部署架构&#xff0c;使得在云环境中管理和扩展容器化应用变得更加容易。这个架构的核心是AWS EKS&#xff08;Elastic Kubernetes Service&#xff09;&#xff0c;它是…

[Pro Git#2] 分支管理 | branch fix_bug , feature | 处理合并冲突

目录 一、Issue模板文件 二、Pull Requests模板文件 分支管理 1. 理解分支 2. 创建与管理分支 1. 切换分支与提交历史 2. 合并分支 3. 删除分支 4. 解决合并冲突 6. 查看分支合并情况 快速创建并切换分支 分支管理策略 分支合并模式 分支管理原则 日常开发环境 …

Acwing 基础算法课 数学知识 筛法求欧拉函数

【G09 筛法求欧拉函数】https://www.bilibili.com/video/BV1VP411p7Bs?vd_source57dbd16b8c7c2ad258cccce5966c5be8 闫总真是把听者当数学系转cs的来讲&#xff0c;菜逼完全听不懂&#xff0c;只能其他地再搜 欧拉函数 φ ( n ) \varphi(n) φ(n)&#xff1a;1~n中与n互质的数…

SpringCloudAlibaba技术栈-Higress

1、什么是Higress? 云原生网关&#xff0c;干啥的&#xff1f;用通俗易懂的话来说&#xff0c;微服务架构下Higress 就像是一个智能的“交通警察”&#xff0c;它站在你的网络世界里&#xff0c;负责指挥和调度所有进出的“车辆”&#xff08;也就是数据流量&#xff09;。它的…

# 光速上手 - JPA 原生 sql DTO 投影

前言 使用 JPA 时&#xff0c;我们一般通过 Entity 进行实体类映射&#xff0c;从数据库中查询出对象。然而&#xff0c;在实际开发中&#xff0c;有时需要自定义查询结果并将其直接映射到 DTO&#xff0c;而不是实体类。这种需求可以通过 JPA 原生 SQL 查询和 DTO 投影 来实现…

智能故障诊断和寿命预测期刊推荐

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 基于FFT CNN - BiGRU-Attention 时域、频域特征注意力融合的轴承故障识别模型-CSDN博客 基于FFT CNN - Transformer 时域、频域特征融合的轴承故障识别模型-CSDN博客 P…

MTK抓log方法log机制以及如何抓取log

目录 离线log抓取&#xff1a; adb命令打开mtklog的方法 &#xff1a; 实时log抓取&#xff1a; 设置log等级和打开平台log: 实时抓取&#xff0c;两种方式&#xff1a; Kernel Log: LOG 优先级 logcat 离线log抓取&#xff1a; 1.手机先进入开发者模式 2.进入拨号页面…

人工智能与云计算的结合:如何释放数据的无限潜力?

引言&#xff1a;数据时代的契机 在当今数字化社会&#xff0c;数据已成为推动经济与技术发展的核心资源&#xff0c;被誉为“21世纪的石油”。从个人消费行为到企业运营决策&#xff0c;再到城市管理与国家治理&#xff0c;每个环节都在生成和积累海量数据。然而&#xff0c;数…

如何在 Ubuntu 22.04 上安装 Varnish HTTP 教程

简介 在本教程中&#xff0c;我们将学习如何在 Ubuntu 22.04 服务器上安装和配置 Varnish HTTP。 Varnish 是一款高性能的 HTTP 加速器&#xff0c;旨在提高内容密集型动态网站的速度。它通过将网页缓存在内存中来工作&#xff0c;从而减少 Web 服务器的负载&#xff0c;并显…

AI辅助编码提高病案首页主要诊断编码正确率数据优化方法(2025增量优化版附python源代码)

一、引言 1.1 研究背景与意义 在医疗信息化进程中,病案首页作为病历信息的核心浓缩,承载着疾病分类、医疗统计、医保结算等关键任务,其主要诊断编码的准确性至关重要。准确的编码不仅是医疗质量评估、科研数据分析的基石,更是合理分配医疗资源、保障医保精准支付的关键依…

CSES-1135 Distance Queries

题目传送门https://vjudge.net/problem/CSES-1135#authorGPT_zh 解题思路 题目让我们求树上两个点的距离。 那么就可以转化为两点到其 LCA 的距离之和。 代码 #include<bits/stdc.h> using namespace std;int n,q; vector<int> g[200001]; int dis[200001],dep…

「Mac畅玩鸿蒙与硬件49」UI互动应用篇26 - 数字填色游戏

本篇教程将带你实现一个数字填色小游戏&#xff0c;通过简单的交互逻辑&#xff0c;学习如何使用鸿蒙开发组件创建趣味性强的应用。 关键词 UI互动应用数字填色动态交互逻辑判断游戏开发 一、功能说明 数字填色小游戏包含以下功能&#xff1a; 数字选择&#xff1a;用户点击…

001__VMware软件和ubuntu系统安装(镜像)

[ 基本难度系数 ]:★☆☆☆☆ 一、Vmware软件和Ubuntu系统说明&#xff1a; a、Vmware软件的说明&#xff1a; 官网&#xff1a; 历史版本&#xff1a; 如何下载&#xff1f; b、Ubuntu系统的说明&#xff1a; 4、linux系统的其他版本&#xff1a;红旗(redhat)、dibian、cent…

【NebulaGraph】变化的多跳查询

【NebulaGraph】变化的多跳查询 1. 需求2. 解决方案2.1 确定查询结构2.2 构建查询语句 3. 追加需求&#xff1a;如果增加每一跳都要指定查询某SPACE下的Tag&#xff0c;或者不查询某个Tag怎么办 1. 需求 存在多跳请求&#xff0c;其中每一跳是从上一跳查询结果为基础的。但是 …