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

news2025/1/19 22:07:27

一、引言

在计算机网络通信领域,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 1024

int 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 1024

int 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 1024

int 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 1024

int 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 1024

int 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 1024

int 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 1024

int 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 1024

int 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!

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

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

相关文章

macOS安装的Ubuntu 20 VM虚拟机扩充磁盘的便捷方式

文章目录 说明操作一 VM扩充虚拟磁盘二 ubuntu系统调整分区 说明 建议ubuntu虚拟机安装图形化界面&#xff0c;方便磁盘管理。如果你安装的debian12&#xff0c;那可能需要使用命令行的方式&#xff0c;本人选择放弃&#xff0c;操作太复杂&#xff01; 操作 一 VM扩充虚拟磁…

关于机器学习的一份总结

在之前的文章中分别有详细的关于机器学习中某一学习算法的介绍&#xff0c;但缺少一个总体关于机器学习的总结&#xff0c;所以在这篇文中就是关于机器学习的一份总结。 在最近的日子中&#xff0c;人工智能日益火热起来&#xff0c;而机器学习是其中举足轻重的一部分&#xf…

idea中远程调试中配置的参数说明

Ⅰ 远程调试中配置的端口号与服务本身端口号区别 一、远程调试中配置端口号的作用 在 IDEA 中进行远程调试时配置的端口号主要用于建立开发工具&#xff08;如 IDEA&#xff09;和远程服务之间的调试连接。当你启动远程调试时&#xff0c;IDEA 会监听这个配置的端口号&#xf…

初识JVM HotSopt 的发展历程

目录 导学 目前企业对程序员的基本要求 面向的对象 实战 学习目标 JVM 是什么 JVM 的三大核心功能 各大 JVM look 看一下虚拟机 HotSopt 的发展历程 总结 导学 目前企业对程序员的基本要求 面向的对象 实战 学习目标 JVM 是什么 JVM 的三大核心功能 即时编译 主要是…

3. 后端验证前端Token

书接上回&#xff0c;后端将token返回给前端&#xff0c;前端存入cookie&#xff0c;每次前端给后端发送请求&#xff0c;后端是如何验证的。 若依是用过滤器来实现对请求的验证&#xff0c;过滤器的简单理解是每次发送请求的时候先发送给过滤器执行逻辑判断以及处理&#xff0…

系统思考—系统性抛弃过去成功的经验

“成功的经验就是最好的老师。” 这句话常听&#xff0c;但在快速变化的市场中&#xff0c;过去的成功可能正是你眼前困境的根源。曾经有效的方法&#xff0c;今天或许已经不适用。要突破瓶颈&#xff0c;企业必须做出艰难的选择——放下过去的成功模式&#xff0c;拥抱未来的…

【MySQL】简单解析一条SQL更新语句的执行过程

1. 更新语句执行流程概述 在 MySQL 中&#xff0c;一条更新语句&#xff08;如 update T set cc1 where ID2&#xff09;的执行涉及多个关键步骤&#xff0c;与查询语句类似&#xff0c;会经过连接器、分析器、优化器、执行器等 Server 层模块&#xff0c;最终到达存储引擎&…

C#与AI的共同发展

C#与人工智能(AI)的共同发展反映了编程语言随着技术进步而演变&#xff0c;以适应新的挑战和需要。自2000年微软推出C#以来&#xff0c;这门语言经历了多次迭代&#xff0c;不仅成为了.NET平台的主要编程语言之一&#xff0c;还逐渐成为构建各种类型应用程序的强大工具。随着时…

mono3d汇总

lidar坐标系 lidar坐标系可以简单归纳为标准lidar坐标系和nucense lidar坐标系&#xff0c;参考链接。这个坐标系和车辆的ego坐标系是一致的。 标准lidar坐标系 opendet3d&#xff0c;mmdetection3d和kitt都i使用了该坐标系 up z^ x front| /| /left y <------ 0kitti采…

支持向量机算法(三):非线性支持向量原理层层拆解,精读公式每一处细节

支持向量机算法&#xff08;一&#xff09;&#xff1a;像讲故事一样讲明白它的原理及实现奥秘-CSDN博客 支持向量机算法&#xff08;二&#xff09;&#xff1a;层层拆解&#xff0c;精读公式每一处细节-CSDN博客 支持向量机算法&#xff08;一&#xff09;、算法&#xff0…

LLM - 大模型 ScallingLaws 的迁移学习与混合训练(PLM) 教程(3)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145212097 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

数据可视化:让数据讲故事的艺术

目录 1 前言2 数据可视化的基本概念2.1 可视化的核心目标2.2 传统可视化手段 3 数据可视化在知识图谱中的应用3.1 知识图谱的可视化需求3.2 知识图谱的可视化方法 4 数据可视化叙事&#xff1a;让数据讲故事4.1 叙事可视化的关键要素4.2 数据可视化叙事的实现方法 5 数据可视化…

数据库开发支持服务

文章目录 前言适用产品服务范围前提条件责任矩阵交互项目 服务流程交付件项目完成标志 前言 数据库开发支持服务是为了达成客户业务系统开发、测试、上线运行提供的具体技术支撑&#xff0c;内容包括数据库开发指导、性能调优、第三方平台对接支持、应用对接与上线支持等。数据…

2024年,我的技术探索与成长之路

2024年&#xff0c;我的技术探索与成长之路 2024年已经过去&#xff0c;作为一名技术爱好者和写作者&#xff0c;我回顾了过去一年在博客上记录的点滴&#xff0c;感慨良多。这一年&#xff0c;我不仅见证了技术的飞速发展&#xff0c;也在不断学习和实践中找到了自己的成长方向…

机器学习经典无监督算法——聚类K-Means算法

目录 算法原理 算法步骤 算法API 算法导入 API参数理解 算法实现 算法原理 Kmeans 算法是一种无监督的聚类算法&#xff0c;目的是将数据集中的样本划分到 K 个不同的簇中。 聚类&#xff1a;将数据集中相似的数据点归为一组或一个簇的过程。 数据集&#xff1a;一组相…

【MySQL索引:B+树与页的深度解析】

文章目录 MySQL索引&#xff1a;B树与页的深度解析1. 索引使用的数据结构——B树1.1 B树介绍1.2 B树的特点1.3 B树和B树的对比 2. MySQL中的页2.1 页的介绍2.2 页主体2.3 页目录2.4 B树在MySQL索引中的应用 MySQL索引&#xff1a;B树与页的深度解析 在MySQL数据库中&#xff0…

新阿里云买服务器配置需手动配置80端口

新买阿里云服务器需手动配置80&#xff0c;端口才可以访问nginx CentOS系统 安装nginx 1. 安装 Nginx yum install nginx 2. 启动 Nginx 服务 systemctl start nginx 3. 修改默认网页 cd /usr/share/nginx/ echo "666" >index.html cat index.html 访问ngin最后…

机器学习——什么是代价函数? 下

“上次课讲了机器学习的模型表示,讲了一个线性模型的例子,那怎样在可能的拟合直线里选择一条最合适的呢?有没有数学的方法让这个直线合适还是不合适变得可以量化呢?这就要说代价函数了。” 本次课前半段内容非常简单,带领我们一起复习初中平面几何的知识,后半段给出了代价…

LeetCode - #187 Swift 实现重复的DNA序列

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

ReactiveReactor Core

Reactive&Reactor Core 一、概述1、问题2、优势3、发展 二、Reactive Streams1、依赖2、API 三、Project Reactor1、概述2、并发模型3、入门1、依赖2、Flux和Mono3、空流&错误流 4、订阅响应式流1、常见订阅2、自定义订阅 5、API1、index2、timestamp3、any4、map5、fi…