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

UDP 单播、多播、广播:原理、实践

一、引言

在计算机网络通信领域,UDP(User Datagram Protocol,用户数据报协议)是一种重要的传输层协议。它以无连接、低开销的特点,在众多实时性要求高的应用场景中发挥关键作用。UDP 支持单播、多播和广播三种通信模式,每种模式都有其独特的应用场景和工作原理。深入理解这些通信模式,对于开发高效的网络应用程序至关重要。

二、UDP 基础概述

UDP 是一种无连接的传输层协议,它在网络层 IP 协议的基础上,为应用层提供了简单的数据传输服务。与面向连接的 TCP(Transmission Control Protocol)协议不同,UDP 不保证数据的可靠传输、顺序交付以及数据的完整性。然而,UDP 的这些特性使得它在一些对实时性要求较高,对数据准确性要求相对较低的场景中具有显著优势,如实时音频和视频流、在线游戏、网络管理等。

UDP 数据报由首部和数据两部分组成。首部长度固定为 8 字节,包含四个字段:

  1. 源端口号(16 位):标识发送端应用程序的端口,用于接收端回发数据。
  2. 目的端口号(16 位):标识接收端应用程序的端口,用于确定数据的接收方。
  3. 长度(16 位):UDP 数据报的总长度,包括首部和数据部分,最小值为 8 字节(仅首部)。
  4. 校验和(16 位):用于检测数据报在传输过程中是否发生错误,但校验和是可选的,若不使用则该字段设为全零。

三、UDP 单播

3.1 概念描述

UDP 单播是一种一对一的通信方式,发送端向特定的一个接收端发送数据。在这种通信模式下,发送端在 UDP 数据报的首部中明确指定接收端的 IP 地址和端口号。网络设备根据数据报中的目的 IP 地址,通过路由算法将数据报转发到目标接收端。单播通信的特点是数据传输的针对性强,只有目标接收端能够接收到数据,适用于大多数需要精确通信的场景,如客户端 - 服务器模型的应用程序。

3.2 示例代码实现

3.2.1 发送端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(buffer, 0, sizeof(buffer));// 设置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr(SERVER_IP);char *msg = "Hello, Server!";sendto(sockfd, (const char *)msg, strlen(msg), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));printf("Message sent to server: %s\n", msg);close(sockfd);return 0;
}
3.2.2 接收端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr, cliaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 设置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(PORT);// 绑定套接字到地址if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);}socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);buffer[n] = '\0';printf("Message received from client: %s\n", buffer);close(sockfd);return 0;
}

3.3 编译和测试过程

  1. 编译

    • 在终端中,切换到包含 udp_unicast_sender.cudp_unicast_receiver.c 文件的目录。
    • 编译发送端代码:gcc -o udp_unicast_sender udp_unicast_sender.c
    • 编译接收端代码:gcc -o udp_unicast_receiver udp_unicast_receiver.c
  2. 测试

    • 首先在一个终端中运行接收端程序:./udp_unicast_receiver
    • 然后在另一个终端中运行发送端程序:./udp_unicast_sender
    • 接收端将显示接收到的消息:Message received from client: Hello, Server!

四、UDP 广播

4.1 概念描述

UDP 广播是一种一对所有的通信方式,发送端向网络中的所有设备发送数据。广播地址分为两种类型:有限广播和直接广播。

  • 有限广播:使用地址 255.255.255.255,它是一种受限的广播地址,仅在本地网络内进行广播,路由器不会转发以有限广播地址为目的地址的数据包。
  • 直接广播:网络地址的主机位全为 1 的地址。例如,对于网络 192.168.1.0/24,其直接广播地址为 192.168.1.255。直接广播数据包可以被路由器转发到指定网络的所有主机。

4.2 原理

4.2.1 有限广播原理
  1. 发送端

    • 发送端创建 UDP 套接字,并设置套接字选项以允许广播(setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable))),其中 broadcastEnable 为一个非零值,通常设为 1。
    • 构造 UDP 数据报,将目的 IP 地址设置为 255.255.255.255,目的端口号设置为接收端监听的端口号。
    • 使用 sendto 函数发送数据报,数据报将在本地网络内广播,所有监听该端口的设备都能接收。
  2. 接收端

    • 接收端创建 UDP 套接字,并绑定到指定的端口号。
    • 使用 recvfrom 函数接收数据报,当有广播数据到达时,接收端就能接收到。
4.2.2 直接广播原理
  1. 发送端

    • 同样,发送端先创建 UDP 套接字并设置允许广播选项。
    • 构造 UDP 数据报时,将目的 IP 地址设置为目标网络的直接广播地址,目的端口号设置为接收端监听的端口号。
    • 使用 sendto 函数发送数据报,路由器会将该数据报转发到目标网络的所有主机。
  2. 接收端

    • 接收端在目标网络内,创建 UDP 套接字并绑定到指定端口号。
    • 使用 recvfrom 函数接收数据报,接收来自发送端的广播数据。

4.3 流程示意图

4.3.1 有限广播流程示意图
设置套接字为广播模式
发送有限广播数据报
广播数据
广播数据
广播数据
发送端
构造有限广播数据报 目的地址255.255.255.255
本地网络
接收端1
接收端2
接收端3
4.3.2 直接广播流程示意图
设置套接字为广播模式
发送直接广播数据报
路由器转发数据报
广播数据
广播数据
广播数据
发送端
构造直接广播数据报 目的地址 目标网络广播地址
网络 含路由器
目标网络
接收端1
接收端2
接收端3

4.4 示例代码实现

4.4.1 有限广播发送端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define LIMITED_BROADCAST_IP "255.255.255.255"
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}int broadcastEnable = 1;// 设置套接字选项以允许广播if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) {perror("setsockopt failed");close(sockfd);exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(buffer, 0, sizeof(buffer));// 设置有限广播地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr(LIMITED_BROADCAST_IP);char *msg = "Hello, Local Network!";sendto(sockfd, (const char *)msg, strlen(msg), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));printf("Limited broadcast message sent: %s\n", msg);close(sockfd);return 0;
}
4.4.2 有限广播接收端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr, cliaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 设置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(PORT);// 绑定套接字到地址if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);}socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);buffer[n] = '\0';printf("Limited broadcast message received: %s\n", buffer);close(sockfd);return 0;
}
4.4.3 直接广播发送端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define DIRECT_BROADCAST_IP "192.168.1.255"
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}int broadcastEnable = 1;// 设置套接字选项以允许广播if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable)) < 0) {perror("setsockopt failed");close(sockfd);exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(buffer, 0, sizeof(buffer));// 设置直接广播地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr(DIRECT_BROADCAST_IP);char *msg = "Hello, 192.168.1.0 Network!";sendto(sockfd, (const char *)msg, strlen(msg), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));printf("Direct broadcast message sent: %s\n", msg);close(sockfd);return 0;
}
4.4.4 直接广播接收端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr, cliaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 设置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(PORT);// 绑定套接字到地址if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);}socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);buffer[n] = '\0';printf("Direct broadcast message received: %s\n", buffer);close(sockfd);return 0;
}

4.5 编译和测试过程

  1. 编译
    • 有限广播
      • 在终端中,切换到包含 udp_limited_broadcast_sender.cudp_limited_broadcast_receiver.c 文件的目录。
      • 编译发送端代码:gcc -o udp_limited_broadcast_sender udp_limited_broadcast_sender.c
      • 编译接收端代码:gcc -o udp_limited_broadcast_receiver udp_limited_broadcast_receiver.c
    • 直接广播
      • 切换到包含 udp_direct_broadcast_sender.cudp_direct_broadcast_receiver.c 文件的目录。
      • 编译发送端代码:gcc -o udp_direct_broadcast_sender udp_direct_broadcast_sender.c
      • 编译接收端代码:gcc -o udp_direct_broadcast_receiver udp_direct_broadcast_receiver.c
  2. 测试
    • 有限广播
      • 首先在本地网络内的多个终端中运行接收端程序:./udp_limited_broadcast_receiver
      • 然后在另一个终端中运行发送端程序:./udp_limited_broadcast_sender
      • 每个接收端都将显示接收到的有限广播消息:Limited broadcast message received: Hello, Local Network!
    • 直接广播
      • 在目标网络(192.168.1.0/24 为例)内的多个终端中运行接收端程序:./udp_direct_broadcast_receiver
      • 在可以向该目标网络发送直接广播的设备上运行发送端程序:./udp_direct_broadcast_sender
      • 目标网络内的每个接收端都将显示接收到的直接广播消息:Direct broadcast message received: Hello, 192.168.1.0 Network!

五、UDP 多播

5.1 概念描述

UDP 多播(也称为组播)是一种一对多的通信方式,发送端向一组特定的接收端发送数据。这组接收端通过加入同一个多播组来接收数据。多播使用 D 类 IP 地址(范围是 224.0.0.0 到 239.255.255.255)来标识多播组。发送端将数据发送到多播组的 IP 地址,网络会将数据转发给组内的所有成员。多播适用于一些需要向特定的一组设备发送相同数据的场景,如在线视频会议、流媒体分发等。与广播不同,多播不会向网络中的所有设备发送数据,只有加入了相应多播组的设备才会接收数据,这样可以减少网络流量,提高传输效率。

5.2 原理

  1. 发送端

    • 发送端创建 UDP 套接字。
    • 构造 UDP 数据报时,将目的 IP 地址设置为多播组的 IP 地址,目的端口号设置为接收端监听的端口号。
    • 使用 sendto 函数将数据报发送出去,网络会根据多播路由协议将数据转发到多播组的成员。发送端不需要关心组内成员的具体 IP 地址,只需要知道多播组的地址。
  2. 接收端

    • 接收端创建 UDP 套接字,并绑定到指定的端口号。
    • 为了加入多播组,接收端需要使用 setsockopt 函数设置套接字选项。具体来说,需要设置 IP_ADD_MEMBERSHIP 选项,代码如下:
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);
mreq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {perror("setsockopt failed");close(sockfd);exit(EXIT_FAILURE);
}
  • 这里,mreq 结构体包含多播组的 IP 地址和本地接口地址。通过设置 IP_ADD_MEMBERSHIP 选项,接收端通知操作系统将该套接字加入指定的多播组。之后,接收端使用 recvfrom 函数接收数据报,就能接收到发往该多播组的所有数据。

5.3 流程示意图

构造多播数据报
多播数据
转发多播数据
转发多播数据
多播数据
发送端
发送多播数据
网络
接收端1 已加入组
接收端2 已加入组
未加入组的设备 忽略

5.4 示例代码实现

5.4.1 多播发送端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define MULTICAST_IP "224.1.1.1"
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(buffer, 0, sizeof(buffer));// 设置多播地址servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr(MULTICAST_IP);char *msg = "Hello, Multicast Group!";sendto(sockfd, (const char *)msg, strlen(msg), MSG_CONFIRM, (const struct sockaddr *)&servaddr, sizeof(servaddr));printf("Multicast message sent: %s\n", msg);close(sockfd);return 0;
}
5.4.2 多播接收端代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define PORT 8080
#define MULTICAST_IP "224.1.1.1"
#define BUFFER_SIZE 1024int main(int argc, char const *argv[]) {int sockfd;struct sockaddr_in servaddr, cliaddr;struct ip_mreq mreq;char buffer[BUFFER_SIZE];// 创建 UDP 套接字if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {perror("socket creation failed");exit(EXIT_FAILURE);}memset(&servaddr, 0, sizeof(servaddr));memset(&cliaddr, 0, sizeof(cliaddr));// 设置服务器地址servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = INADDR_ANY;servaddr.sin_port = htons(PORT);// 绑定套接字到地址if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {perror("bind failed");close(sockfd);exit(EXIT_FAILURE);}// 设置多播组地址和本地接口地址mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP);mreq.imr_interface.s_addr = INADDR_ANY;// 加入多播组if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {perror("setsockopt failed");close(sockfd);exit(EXIT_FAILURE);}socklen_t len = sizeof(cliaddr);int n = recvfrom(sockfd, (char *)buffer, BUFFER_SIZE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);buffer[n] = '\0';printf("Multicast message received: %s\n", buffer);close(sockfd);return 0;
}

5.5 编译和测试过程

  1. 编译

    • 在终端中,切换到包含 udp_multicast_sender.cudp_multicast_receiver.c 文件的目录。
    • 编译发送端代码:gcc -o udp_multicast_sender udp_multicast_sender.c
    • 编译接收端代码:gcc -o udp_multicast_receiver udp_multicast_receiver.c
  2. 测试

    • 首先在多个终端中运行接收端程序(模拟多播组成员):./udp_multicast_receiver
    • 然后在另一个终端中运行发送端程序:./udp_multicast_sender
    • 每个接收端都将显示接收到的多播消息:`Multicast message received: Hello, Multicast Group!

相关文章:

UDP 单播、多播、广播:原理、实践

一、引言 在计算机网络通信领域&#xff0c;UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种重要的传输层协议。它以无连接、低开销的特点&#xff0c;在众多实时性要求高的应用场景中发挥关键作用。UDP 支持单播、多播和广播三种通信模式…...

深入浅出:Go语言中的bytes包与字节串操作详解

标题:深入浅出:Go语言中的bytes包与字节串操作详解 引言 在Go语言的世界里,bytes包是一个非常重要的标准库,它为开发者提供了高效处理字节切片(byte slice)的功能。无论是处理二进制数据、UTF-8编码的字符串,还是进行高效的数据读写操作,bytes包都扮演着不可或缺的角色…...

数据库存储上下标符号,sqlserver 2008r2,dm8

sqlserver 2008r2&#xff1a; 数据类型需要用nvarchar插入数据时字符串前需要用N create table test( col1 varchar(50), col2 nvarchar(50) ) insert into test(col1,col2) values(U⁴⁵⁶⁷⁸⁹⁰D₁₂₃₄₅₆₇₈₉₀,U⁴⁵⁶⁷⁸⁹⁰D₁₂₃₄₅₆₇₈₉₀) insert into…...

LabVIEW串口通信调试与数据接收问题

在使用LabVIEW进行串口通信时&#xff0c;常常会遇到无法接收数据的情况。这可能与串口设置、连接、设备响应等多方面因素相关。本文将详细讨论如何使用LabVIEW进行串口通信&#xff0c;并提供常见问题的排查与解决方法&#xff0c;帮助用户更高效地进行数据接收调试。通过调整…...

oneplus3t-lineage-14编译-android7

lineageOS-14(android7)的开发者模式/usb调试(adb)有root功能, 而lineageOS-16(android9)无 oneplus3t-lineage-14编译-android7 1 清华linageos镜像 x lineage-14.1-20180223-nightly-oneplus3-signed.zip ntfs分区挂载为普通用户目录 , ext4分区挂载为普通用户目录 bfs…...

存储过程(SQL)

1.存储过程 存储过程&#xff08;Stored Procedure&#xff09;是一组为了完成特定功能的SQL语句集&#xff0c;经编译后存储在数据库中&#xff0c;用户通过指定存储过程的名字并给定参数&#xff08;如果该存储过程带有参数&#xff09;来调用执行它。 2.MySQL存储过程创建…...

【I/O编程】UNIX文件基础

IO编程的本质是通过 API 操作 文件。 什么是 IO I - Input 输入O - Output 输出 这里的输入和输出都是站在应用&#xff08;运行中的程序&#xff09;的角度。外部特指文件。 这里的文件是泛指&#xff0c;并不是只表示存在存盘中的常规文件。还有设备、套接字、管道、链接…...

完美解决phpstudy安装后mysql无法启动

phpstudy数据库无法启动有以下几个原因。 **一、**自己在电脑上安装了MySQL数据库,MySQL的服务名为MySQL,这会与phpstudy的数据库的服务名发生冲突&#xff0c;从而造成phpstudy中的数据库无法启动&#xff0c;这时我们只需要将自己安装的MySQL的服务名改掉就行。 但是&#…...

自己造轮子-基于Ceres的GNSS-INS松耦合组合导航算法

之前硕士期间的研究课题涉及到GNSS-INS组合导航&#xff0c;入门看的武汉大学牛老师团队的KF-GINS&#xff0c;不得不说&#xff0c;大组的东西还是很棒的&#xff0c;很适合组合导航入门&#xff0c;KF-GINS主要是基于ESKF的GNSS/INS松耦合组合导航系统&#xff0c;博主就不在…...

「实战应用」如何为DHTMLX JavaScript 甘特图添加进度线

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 今天&#xff0c;您将学习如何使用进度线补充JavaScript 甘特图&#xff0c;以便于监控项目进度。 DHTMLX Gantt 最新试用版下载 …...

MySQL面试题2025 每日20道

1、MySQL 中的数据排序是怎么实现的&#xff1f; 简单 在 MySQL 中&#xff0c;数据排序是通过 ORDER BY 子句来实现的。当你执行一个查询语句时&#xff0c;可以在 SELECT 语句的末尾添加 ORDER BY 来指定按照哪个列进行排序&#xff0c;以及升序&#xff08;ASC&#xff09;…...

HTML学习笔记(4)

目录 一、背景相关样式 二、定位position 三、javascript 1、变量的定义 2、数据类型 3、绑定事件 一、背景相关样式 background-image: url(); // 背景图片 background-repeat: repeat; // 背景图片是否平铺 no-repeat background-size: 200px; // 背景图片尺寸 cover把…...

解决 MySQL 服务无法启动:failed to restart mysql.service unit not found

目录 前言1. 问题描述2. 问题分析3. 解决步骤 3.1 检查 MySQL 服务文件3.2 备份旧的服务文件3.3 启动 MySQL 服务3.4 验证服务状态 4. 总结结语 前言 在日常使用 MySQL 数据库时&#xff0c;有时候可能会遇到服务无法正常启动的问题。这类问题通常出现在系统更新或者服务配置…...

在 Ubuntu 上安装 Nginx 的详细指南

在Ubuntu系统中从源码安装Nginx可以让您自定义Nginx的编译选项和模块&#xff0c;以满足特定需求。以下是详细的步骤指南&#xff1a; 前提条件 更新系统包列表 sudo apt update sudo apt upgrade -y安装必要的依赖包 sudo apt install -y build-essential libpcre3 libpcre3-…...

58,【8】BUUCTF [PwnThyBytes 2019]Baby_SQL1

进入靶场 和2次注入的页面很像 不过养成查看源代码的好习惯 先访问source.zip 下载后解压&#xff0c;发现两个文件 第一个文件夹打开又有4个PHP文件 那还是先看index.php文件好了 有PHP和HTML两部分&#xff0c;下面是PHP部分代码&#xff08;HTML太长了&#xff0c;先放一…...

2.1 三个世界”与“图灵测试”:人工智能与人类智能的深度探索

“三个世界”与“图灵测试”:人工智能与人类智能的深度探索 人工智能的研究和发展,尤其是对其认知能力和智能表现的探索,早在20世纪中期就已成为科学家的热议话题。随着技术的进步,学者们提出了许多思想框架来理解人工智能的运作及其与人类智能的关系。其中,“三个世界”…...

基于微信小程序的优购电商系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

JS宏进阶: 工厂函数与构造函数

一、构造函数 在JavaScript中&#xff0c;构造函数是一种用于创建和初始化对象的特殊函数。构造函数的名字通常以大写字母开头&#xff0c;以区分于普通函数。通过new关键字调用构造函数&#xff0c;可以创建一个新的实例对象&#xff0c;并自动执行构造函数内部的代码来初始化…...

【Linux】线程全解:概念、操作、互斥与同步机制、线程池实现

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长&#xff0c;行则将至 目录 &#x1f4da;一、线程概念 &#x1f4d6; 回顾进程 &#x1f4d6; 引入线程 &#x1f4d6; 总结 &a…...

关于ubuntu命令行连接github失败解决办法

如果发现ping github.com有问题 使用sudo gedit /ect/hosts 打开host文件 添加 140.82.114.4 github.com 发现使用git 克隆失败&#xff0c;出现 aliaubuntu:~/文档/ctest$ git clone https://github.com/LearningInfiniTensor/learning-cxx.git 正克隆到 ‘learning-cxx’… …...

# [游戏开发] [Unity游戏开发]3D滚球游戏设计与实现教程

在这篇文章中,我们将通过一个简单的3D滚球游戏的设计与实现,讲解游戏开发中的一些关键概念和技术。游戏的核心目标是让玩家控制一个小球在跑道上左右移动,躲避障碍物并尽量向前跑,直到成功或失败。通过这一过程,我们会涉及到功能点分析、场景搭建、主体控制、游戏机制等多…...

强推未发表!3D图!Transformer-LSTM+NSGAII工艺参数优化、工程设计优化!

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Transformer-LSTMNSGAII多目标优化算法&#xff0c;工艺参数优化、工程设计优化&#xff01;&#xff08;Matlab完整源码和数据&#xff09; Transformer-LSTM模型的架构&#xff1a;输入层&#xff1a;多个变量作…...

Flutter中的事件冒泡处理

在 Flutter 中&#xff0c;GestureDetector 的点击事件默认是冒泡的&#xff0c;即如果嵌套了多个 GestureDetector&#xff0c;点击事件会从最内层的 GestureDetector 开始触发&#xff0c;然后依次向外层传递。如果你希望控制事件的优先级或阻止事件冒泡&#xff0c;可以使用…...

昇腾环境ppstreuct部署问题记录

测试代码 我是在华为昇腾910B3上测试的PPStructure。 import os import cv2 from PIL import Image #from paddleocr import PPStructure,draw_structure_result,save_structure_res from paddleocr_asyncio import PPStructuretable_engine PPStructure(show_logTrue, imag…...

基于 Python 的财经数据接口库:AKShare

AKShare 是基于 Python 的财经数据接口库&#xff0c;目的是实现对股票、期货、期权、基金、外汇、债券、指数、加密货币等金融产品的基本面数据、实时和历史行情数据、衍生数据从数据采集、数据清洗到数据落地的一套工具&#xff0c;主要用于学术研究目的。 安装 安装手册见…...

电力场景红外测温图像绝缘套管分割数据集labelme格式2436张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;2436 标注数量(json文件个数)&#xff1a;2436 标注类别数&#xff1a;1 标注类别名称:["arrester"] 每个类别标注的框数&am…...

数字艺术类专业人才供需数据获取和分析研究

本文章所用数据集&#xff1a;数据集 本文章所用源代码&#xff1a;源代码和训练好的模型 第1章 绪论 1.1研究背景及意义 随着社会经济的迅速发展和科技的飞速进步&#xff0c;数字艺术类专业正逐渐崛起&#xff0c;并呈现出蓬勃发展的势头。数字艺术作为创作、设计和表现形式的…...

Java中json的一点理解

一、Java中json字符串与json对象 1、json本质 json是一种数据交换格式。 常说的json格式的字符串 > 发送和接收时都只是一个字符串&#xff0c;它遵循json这种格式。 2、前后端交互传输的json是什么&#xff1f; 前后端交互传输的json都是json字符串 比如&#xff1a;…...

Vue项目搭建教程超详细

目录 一. 环境准备 1. 安装node.js 2. 安装Vue cli 二. 创建 Vue 2 项目 1. 命令行方式 2. vue ui方式 一. 环境准备 1. 安装node.js 可参考node.js卸载与安装超详细教程-CSDN博客 2. 安装Vue cli npm install -g vue/cli检查是否安装成功 vue --version Vue CLI …...

2025年01月蓝桥杯Scratch1月stema选拔赛真题—美丽的图形

美丽的图形 编程实现美丽的图形具体要求: 1)点击绿旗&#xff0c;角色在舞台中心&#xff0c;如图所示&#xff1b; 2)1秒后&#xff0c;绘制一个边长为 140的红色大正方形&#xff0c;线条粗细为 3&#xff0c;正方形的中心为舞台中心&#xff0c;如图所示; 完整题目可点击下…...

wordpress 获取分类文章/seo推广的常见目的有

http://www.cnblogs.com/newpanderking/archive/2011/10/03/2198648.html 讲得很详细。。。我没明白。...

武汉京伦科技网站建设/如何创建个人网站免费

参考官网&#xff1a; https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html 一、版本升级 gradle升级到4.1android gradle plugin升级到3.0.0buildToolsVersion 升级到26.0.2compileSdkVersion升级到26加入google()仓库##gradle升级到4.1 distribu…...

十堰做网站公司/sem是什么意思职业

VMware的安装与Linux操作系统的配置VMware安装Linux安装环境CentOS的下载安装Linux系统虚拟机的创建Linux环境的安装VMware安装 首先我们先安装VMware VMware安装地址 选择【for windows】进行下载 下载完成之后双击进行打开 此时出现这个页面点击【下一步】 点击【我接受许可协…...

网站开发种类/搜索引擎营销是什么意思

os这个模块提供了一种方便的使用操作系统函数的方法。__file__&#xff1a;这个脚本的相对路径。比如说脚本叫做test.py&#xff0c;那print(__file__)输出的结果就是test.py。os.path.realpath(__file__)&#xff1a;这个脚本的绝对路径。os.getcwd()&#xff1a;当前工作区的…...

做公众号模板的网站/win10系统优化工具

原文&#xff1a;http://www.blogcn.com/User8/flier_lu/blog/29042138.html1.3 局部重绘模式的服务器端响应 在第一小节中&#xff0c;我们曾提到 ScriptManager 在重载的 Web.UI.Control.OnInit 事件中&#xff0c;会根据页面请求中 delta true 是否存在&#xff0c;判断当…...

wordpress pdf 下载/中国万网登录入口

《认识计算机》教案设计 [课 题] 认识计算机 [教学目的与要求] (1)能够了解计算机各部分的名称及作用。 (2) 培养学生的观察和自主学习的能力。 [课时安排] 1课时。 [教学重点与难点] (1)计算机是一个由多种设备组合在一起的整体。 (2)正确认识计算机各部分的名称及作用。 [教学…...