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

【网络编程】UDP协议 和 Socket编程

1. UDP的特点

UDP(User Datagram Protocol,用户数据报协议)是互联网协议套件中的一种传输层协议,与广泛使用的TCP(Transmission Control Protocol,传输控制协议)相比,它是一种无连接不可靠的协议。UDP 被用于对传输速度要求较高、但对可靠性要求较低的场景。

2. UDP与TCP的区别

UDP(用户数据报协议)和TCP(传输控制协议)都是传输层协议,负责在网络中传输数据,但它们的设计目标和实现方式有很大的区别。

以下是UDP和TCP的主要区别:

3. UDP的包头格式

在这里插入图片描述

下面是各个字段的解释:

3.1. UDP伪首部(Pseudo Header)

伪首部是用于计算校验和的虚拟头部信息,它不包含在实际传输的数据中,但用于保证数据完整性。伪首部包含如下字段:

  • 32位源IP地址:表示数据包的源IP地址,即发送方的IP地址。
  • 32位目的IP地址:表示数据包的目的IP地址,即接收方的IP地址。
  • 0:固定填充的8位0字段,不使用。
  • 8位协议(17):标识传输协议类型,对于UDP协议来说,这个字段的值是 17
  • 16位UDP长度:表示整个UDP数据报的长度,包括UDP首部和数据部分。

3.2. UDP首部

UDP首部是真正的数据报头部,它包含了与UDP通信相关的基本信息。UDP首部固定为8字节,包含以下字段:

  • 16位源端口号:发送方的端口号,标识发送数据的应用程序。如果不需要,值可以为 0
  • 16位目的端口号:接收方的端口号,表示接收数据的应用程序。
  • 16位UDP长度:表示UDP报文的总长度(包括UDP首部和数据部分)。由于UDP首部固定为8字节,因此长度至少为8。
  • 16位UDP校验和:用于确保UDP数据报在传输过程中没有被损坏。它由UDP伪首部、UDP首部和数据部分计算而得。如果发送方不计算校验和,则该字段可以为 0

3.3. 数据部分

UDP数据报的实际数据内容。数据部分的长度可以根据具体的应用需求而变化,但必须与首部中的UDP长度字段保持一致。

3.4. 填充字节(0)

数据包需要按一定的字节对齐规则(如32位对齐)填充到合适的长度,以确保数据包的完整性和便于传输

3.5. 重点:

  • UDP伪首部并不实际存在于UDP报文中,它仅在计算校验和时使用,用于提供更多的上下文(如IP地址)来验证数据的完整性。
  • UDP首部非常简单,仅有8字节,保证了UDP的轻量和高效。
  • UDP数据:携带的实际传输数据,长度可以根据应用而变化。

这个图展示了UDP协议的简单性和高效性,因为UDP协议不需要复杂的连接管理或传输控制机制。

4. UDP Socket编程流程

在这里插入图片描述

4.1. UDP客户端流程

  • socket():创建一个UDP套接字(Socket)。这是启动UDP通信的第一步,客户端通过调用socket()函数生成一个用于通信的套接字。
  • sendto():向服务器发送数据。客户端使用sendto()函数来将数据报发送到指定的服务器IP地址和端口。这是一个无连接的操作,不需要事先建立连接。
  • 等待响应:客户端调用recvfrom()函数,进入阻塞状态,等待从服务器返回的数据。recvfrom()会接收来自服务器的数据报,函数会在接收到数据后解除阻塞。
  • recvfrom():接收到服务器返回的数据后,继续处理该数据。
  • close():通信完成后,关闭客户端套接字,释放系统资源。

4.1. UDP客户端流程

  • socket():创建一个UDP套接字(Socket)。这是启动UDP通信的第一步,客户端通过调用socket()函数生成一个用于通信的套接字。
  • sendto():向服务器发送数据。客户端使用sendto()函数来将数据报发送到指定的服务器IP地址和端口。这是一个无连接的操作,不需要事先建立连接。
  • 等待响应:客户端调用recvfrom()函数,进入阻塞状态,等待从服务器返回的数据。recvfrom()会接收来自服务器的数据报,函数会在接收到数据后解除阻塞。
  • recvfrom():接收到服务器返回的数据后,继续处理该数据。
  • close():通信完成后,关闭客户端套接字,释放系统资源。

4.2. UDP服务器流程

  • socket():与客户端一样,服务器首先创建一个UDP套接字,通过调用socket()函数。
  • bind():将套接字与指定的IP地址和端口绑定。服务器必须绑定到一个特定的端口上,这样才能接收来自客户端的数据。bind()是服务器端特有的操作,客户端通常不需要显式调用bind()
  • recvfrom():服务器使用recvfrom()接收客户端发送的数据报,并进入阻塞状态,直到接收到数据为止。
  • 处理请求:收到数据后,服务器可以处理这个请求。例如,解析数据、执行相关操作。
  • sendto():处理完成后,服务器通过sendto()向客户端发送响应数据。
  • 继续等待:服务器可以继续调用recvfrom()来接收下一个数据请求。

4.3. 图中的其他元素

  • 阻塞直到收到数据:无论是客户端还是服务器,调用recvfrom()后,程序会进入阻塞状态,等待对方发送数据。这是UDP通信中的常见模式。
  • 数据请求和数据响应:图中显示了客户端向服务器发送请求数据,服务器处理后返回响应数据的流程。

4.4. UDP通信的特点

  • 无连接:UDP协议是无连接的,客户端不需要先与服务器建立连接,直接发送数据。服务器收到数据后可以立即处理。
  • 阻塞模式:图中显示的recvfrom()操作是阻塞的,直到有数据到来才会继续执行。
  • 简单轻量:由于UDP不需要维护连接状态,它比TCP更加简单和轻量,适用于对实时性要求高但对数据可靠性要求较低的场景。

5. UDP代码实现

下面是一个使用C++实现UDP通信的简单示例,包括UDP服务器和客户端。

通过Socket编程,服务器接收客户端发送的消息,并作出回应。

5.1. UDP服务器代码:

#include <iostream>
#include <cstring>   // for memset
#include <sys/socket.h>  // for socket functions
#include <arpa/inet.h>   // for sockaddr_in and inet_ntoa
#include <unistd.h>      // for close#define PORT 8081
#define BUFFER_SIZE 1024int main() {int sockfd;char buffer[BUFFER_SIZE];struct sockaddr_in server_addr, client_addr;socklen_t addr_len = sizeof(client_addr);// 创建UDP Socketsockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}// 配置服务器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;  // IPv4server_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定到本地所有IP地址server_addr.sin_port = htons(PORT);  // 指定端口号// 绑定Socket到地址if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {perror("Bind failed");close(sockfd);exit(EXIT_FAILURE);}std::cout << "UDP server is listening on port " << PORT << std::endl;while (true) {// 接收消息int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client_addr, &addr_len);buffer[n] = '\0';  // 将接收到的数据转换为字符串格式std::cout << "Client: " << buffer << std::endl;// 响应消息const char *response = "Message received";sendto(sockfd, response, strlen(response), 0, (const struct sockaddr *)&client_addr, addr_len);}close(sockfd);return 0;
}

5.2. UDP客户端代码:

#include <iostream>
#include <string>
#include <cstring>     // 使用strerror
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>    // 使用close()#define PORT 8081                      // 定义端口号
#define BUFFER_SIZE 1024               // 定义缓冲区大小
#define IP "110.41.83.50"              // 定义服务器IP地址int main() {int sockfd;char buffer[BUFFER_SIZE];struct sockaddr_in server_addr;// 创建UDP Socketsockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Socket creation failed: " << strerror(errno) << std::endl;return 1;}// 配置服务器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);// 使用inet_pton将IP地址从字符串转换为网络字节顺序if (inet_pton(AF_INET, IP, &server_addr.sin_addr) <= 0) {std::cerr << "Invalid address/ Address not supported" << std::endl;close(sockfd);return 1;}while (true) {// 发送消息到服务器std::string message;std::cout << "Enter message: ";std::getline(std::cin, message);// 发送消息int send_result = sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));if (send_result < 0) {std::cerr << "sendto failed: " << strerror(errno) << std::endl;break;}// 接收服务器的响应socklen_t addr_len = sizeof(server_addr);  // 地址长度参数int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr*)&server_addr, &addr_len);if (n < 0) {std::cerr << "recvfrom failed: " << strerror(errno) << std::endl;break;}buffer[n] = '\0';  // 添加字符串结束符std::cout << "Server: " << buffer << std::endl;  // 输出服务器响应}// 关闭Socketclose(sockfd);return 0;
}

5.3. Windows客户端版本:

  1. 头文件和库的引入

    • 在Windows中需要引入winsock2.hws2tcpip.h,并且需要链接Ws2_32.lib库。
  2. Winsock初始化和清理

    • 在Windows中,使用网络功能之前需要调用WSAStartup()进行初始化,使用完毕后需要调用WSACleanup()释放资源。
  3. Windows和Linux之间的一些函数差异

    • close()在Windows上对应的是closesocket()
    • perror()函数在Windows上不常用,通常使用std::cerr输出错误。
5.3.1. Windows版本的UDP客户端代码:
#include <iostream>
#include <string>
#include <winsock2.h>
#include <ws2tcpip.h>#pragma comment(lib, "Ws2_32.lib")  // 链接Ws2_32.lib库#define PORT 8081                      // 定义端口号
#define BUFFER_SIZE 1024               // 定义缓冲区大小
#define IP "110.41.83.50"              // 定义服务器IP地址,注意需要加上双引号int main() {WSADATA wsaData;SOCKET sockfd;char buffer[BUFFER_SIZE];struct sockaddr_in server_addr;// 初始化Winsockif (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {std::cerr << "WSAStartup failed." << std::endl;return 1;}// 创建UDP Socketsockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd == INVALID_SOCKET) {std::cerr << "Socket creation failed: " << WSAGetLastError() << std::endl;WSACleanup();return 1;}// 配置服务器地址memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(PORT);// 使用inet_pton将IP地址从字符串转换为网络字节顺序if (inet_pton(AF_INET, IP, &server_addr.sin_addr) <= 0) {std::cerr << "Invalid address/ Address not supported" << std::endl;closesocket(sockfd);WSACleanup();return 1;}while (true) {// 发送消息到服务器std::string message;std::cout << "Enter message: ";std::getline(std::cin, message);// 发送消息int send_result = sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));if (send_result == SOCKET_ERROR) {std::cerr << "sendto failed: " << WSAGetLastError() << std::endl;break;}// 接收服务器的响应int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, nullptr, nullptr);if (n == SOCKET_ERROR) {std::cerr << "recvfrom failed: " << WSAGetLastError() << std::endl;break;}buffer[n] = '\0';  // 添加字符串结束符std::cout << "Server: " << buffer << std::endl;  // 输出服务器响应}// 关闭Socketclosesocket(sockfd);// 清理WinsockWSACleanup();return 0;
}
5.3.2. 主要修改点说明:
  1. WSAStartup()WSACleanup():这些函数分别在程序开始时初始化Winsock库,结束时清理它。
  2. socket():创建Socket时,错误返回值为INVALID_SOCKET,而不是Linux中的-1
  3. closesocket():在Windows中,用closesocket()代替Linux中的close()函数来关闭套接字。
  4. WSAGetLastError():用于获取最近的套接字操作错误码。

5.4. 函数细节说明

5.4.1. 关于recvfrom函数

recvfrom函数是套接字编程中用于从套接字接收数据的一个函数,特别用于UDP协议下的数据接收。它允许程序从一个未连接的套接字(如UDP套接字)接收数据报。下面是对recvfrom函数及其参数int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, nullptr, nullptr);的详细解释:

函数原型

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  struct sockaddr *src_addr, socklen_t *addrlen);

参数解释

  1. sockfd: 套接字描述符,指定了接收数据的套接字。这个套接字通常是通过socket函数创建的,并且绑定到了一个特定的端口(对于UDP来说)。
  2. buf: 指向数据缓冲区的指针,这个缓冲区用于存储接收到的数据。接收到的数据会被复制到这个缓冲区中。
  3. len: 指定了buf缓冲区的长度,即可以接收的最大数据量(以字节为单位)。
  4. flags: 标志位,用于修改recvfrom的行为。常用的标志包括MSG_PEEK(查看数据但不从队列中移除)、MSG_WAITALL(请求阻塞操作直到接收到完整的请求数据,但这对于UDP来说通常不适用,因为UDP是无连接的、数据报驱动的协议)等。在这个例子中,flags被设置为0,表示使用默认行为。
  5. src_addr: 指向sockaddr结构体的指针,用于存储发送方的地址信息。如果不需要这个信息,可以传递nullptr。在这个例子中,src_addr被设置为nullptr,表示不关心发送方的地址。
  6. addrlen: 指向socklen_t变量的指针,该变量在调用前应该被初始化为src_addr所指向的地址结构的大小。在函数调用后,这个变量会被更新为实际存储在src_addr中的地址结构的大小。如果src_addrnullptr,则addrlen也应该是nullptr。在这个例子中,addrlen被设置为nullptr

返回值

recvfrom函数返回成功接收到的字节数。如果返回0,表示连接已正常关闭(但这对UDP来说并不常见,因为UDP是无连接的)。如果返回-1,表示发生了错误,错误类型可以通过errno来检查。

示例解释

在给出的代码示例中:

int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, nullptr, nullptr);
  • sockfd是一个有效的UDP套接字描述符。
  • buffer是一个足够大的缓冲区,用于存储接收到的数据。
  • BUFFER_SIZEbuffer的大小,即可以接收的最大数据量。
  • flags设置为0,表示使用默认行为。
  • src_addraddrlen都设置为nullptr,表示不关心发送方的地址信息。

n会被赋值为实际接收到的字节数,或者-1表示出错。

5.4.2. 关于sendto函数

sendto函数是套接字编程中用于发送数据的一个函数,特别适用于UDP协议下的数据发送。它允许程序向指定的地址发送数据报。

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,  const struct sockaddr *dest_addr, socklen_t addrlen);

参数解释

  1. sockfd: 套接字描述符,指定了发送数据的套接字。这个套接字通常是通过socket函数创建的,对于UDP来说,它可能还没有通过connect函数与特定的远程地址关联。
  2. buf: 指向数据缓冲区的指针,这个缓冲区包含了要发送的数据。
  3. len: 指定了buf缓冲区的长度,即要发送的数据量(以字节为单位)。在这个例子中,通过strlen(response)来获取response字符串的长度。
  4. flags: 标志位,用于修改sendto的行为。常用的标志包括MSG_CONFIRM(请求确认消息已发送)、MSG_DONTROUTE(绕过路由表直接发送)等。在这个例子中,flags被设置为0,表示使用默认行为。
  5. dest_addr: 指向sockaddr结构体的指针,用于指定接收方的地址信息。这个结构体包含了目标主机的IP地址和端口号。
  6. addrlen: 指定了dest_addr所指向的地址结构的大小。这个值通常是通过sizeof操作符获取的。

返回值

sendto函数返回成功发送的字节数。如果返回-1,表示发生了错误,错误类型可以通过errno来检查

示例解释

在给出的代码示例中:

const char *response = "Message received";  
sendto(sockfd, response, strlen(response), 0, (const struct sockaddr *)&client_addr, addr_len);
  • response是一个指向常量字符串的指针,包含了要发送的消息。
  • sockfd是一个有效的UDP套接字描述符。
  • strlen(response)计算了response字符串的长度,即要发送的数据量。
  • flags设置为0,表示使用默认行为。
  • (const struct sockaddr *)&client_addr是一个指向sockaddr结构体的指针,该结构体包含了接收方的地址信息。这里假设client_addr已经被正确初始化,并且包含了目标主机的IP地址和端口号。
  • addr_lenclient_addr结构体的大小,通常是通过sizeof(client_addr)获取的。

sendto函数被调用时,它会尝试将response字符串发送到由client_addr指定的地址。如果发送成功,它会返回发送的字节数;如果失败,它会返回-1并设置errno来指示错误类型。

5.4.3. <ws2tcpip.h>

<ws2tcpip.h> 是 Windows 的附加头文件,扩展了 Winsock2 的功能,提供了一些与现代网络协议相关的功能和 API。主要包括支持 IPv6 和通用的地址解析功能。

主要功能:

  1. 支持 IPv6
  • 提供了与 IPv6 相关的常量、数据结构和函数,例如:

  • sockaddr_in6:用于表示 IPv6 地址的结构体

  • inet_pton()inet_ntop():分别用于将字符串转换为二进制 IP 地址和将二进制 IP 地址转换为字符串(支持 IPv4 和 IPv6)

  1. 地址解析和管理
  • 提供了现代的地址解析和主机名解析功能:

  • getaddrinfo():根据主机名、服务名获取地址信息,支持 IPv4 和 IPv6 的通用 API

  • freeaddrinfo():释放通过 getaddrinfo() 分配的内存

  • getnameinfo():将地址转换为主机名或服务名

  1. 端口和地址转换函数
  • 提供了 IP 地址和端口号的转换函数,例如:

  • inet_pton():将点分十进制的 IPv4 或 IPv6 地址转换为网络字节序的二进制形式

  • inet_ntop():将二进制的 IP 地址转换为字符串形式

5.4.4. WSADATA 结构体

WSADATA 是 Windows Sockets API(Winsock)中的一个结构体,包含有关 Windows Sockets 的实现版本和系统的配置信息。在调用 WSAStartup() 函数时,应用程序必须传递该结构体的指针,以便 Winsock 初始化并返回相关信息。

WSADATA 结构体定义在 <winsock2.h> 头文件中,具体如下:

typedef struct WSAData {WORD wVersion;          // Winsock实现的版本号WORD wHighVersion;      // 支持的最高版本号char szDescription[WSADESCRIPTION_LEN + 1];  // 描述Winsock的文本字符串char szSystemStatus[WSASYSSTATUS_LEN + 1];   // 当前的状态或配置unsigned short iMaxSockets;                  // 系统允许的最大套接字数unsigned short iMaxUdpDg;                    // 支持的最大UDP数据报大小char* lpVendorInfo;                          // 供应商特定的信息
} WSADATA, *LPWSADATA;
5.4.5. 关于memset

memset 是一个 C/C++ 标准库函数,用于将一块内存区域的内容设置为指定的值。它通常用于初始化数组或结构体,以确保在使用这些数据之前内存中的内容是已知的。memset 函数定义在 <cstring>(C++)或 <string.h>(C)头文件中。

void* memset(void* ptr, int value, size_t num);

参数说明

  • ptr:指向要设置的内存块的指针。
  • value:要设置的值。这个值会被转换为 unsigned char 类型,并且将其填充到内存块中。
  • num:要设置的字节数。

6. UPD的挑战

相关文章:

【网络编程】UDP协议 和 Socket编程

1. UDP的特点 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是互联网协议套件中的一种传输层协议&#xff0c;与广泛使用的TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;相比&#xff0c;它是一种无连接…...

【探寻C++之旅】第十二章:异常

请君浏览 前言1.异常的概念2.异常的使用2.1 抛出与捕获2.2 栈展开2.3 查找匹配的处理代码2.4 简单的异常使用2.5 异常重新抛出 2. 异常的安全问题3. 异常的规范4. 标准库的异常5. 异常处理建议尾声 前言 今天&#xff0c;我们继续踏入追寻C的冒险历程。今天我们让我们来讲讲C中…...

CSS的三大特性:层叠、继承与优先级

CSS作为网页设计的核心语言&#xff0c;其三大核心特性——层叠性、继承性和优先级共同构成了样式表现的底层逻辑。理解这些特性将帮助开发者写出更优雅、更易维护的样式代码。 一、层叠性&#xff08;Cascading&#xff09; 1.1 核心概念 "层叠"指多个样式规则同…...

Spring Cloud 项目中优雅地传递用户信息:基于 Gateway + ThreadLocal 的用户上下文方案

在 Spring Cloud 微服务架构中&#xff0c;我们通常使用 API 网关&#xff08;如 Spring Cloud Gateway&#xff09;作为流量入口&#xff0c;负责统一的用户身份校验和请求路由。本文将介绍一种通用的用户信息传递方案&#xff1a;网关完成认证后通过请求头传递用户信息&#…...

node.js 实战——mongoDB 续一

mongoDB的基本指令 进入mongodb mongo显示当前的所有数据库 show dbs # 或者 show databases切换数据库/进入指定数据库 使用这个命令的时候&#xff0c;是不要求这个数据库是否创建 use 数据库名显示当前数据库 db显示数据库中所有集合 show collections数据库的CRUD的…...

鸟笼效应——AI与思维模型【84】

一、定义 鸟笼效应思维模型指的是人们在偶然获得一件原本不需要的物品后,会为了这件物品的配套或使用需求,进而继续添加更多与之相关但自己原本可能并不需要的东西,仿佛被这个“鸟笼”牵着走,最终陷入一种惯性消费或行为模式的现象。简单来说,就是人们在心理上会有一种自…...

豪越科技消防立库方案:实现应急物资高效管理

在消防救援工作中&#xff0c;应急物资管理是至关重要的一环。然而&#xff0c;当前应急物资管理的现状却令人担忧。传统的应急物资管理方式存在诸多弊端&#xff0c;严重影响了消防救援的效率和效果。 走进一些传统的消防仓库&#xff0c;映入眼帘的往往是杂乱无章的存储场景。…...

简化excel校验提高开发效率

业务背景&#xff1a;上传excel文件进行基础数据校验&#xff0c;然而东西太多写着写着就...自然成了测试的KPI了 解决思路&#xff1a;使用现有的注解处理&#xff0c;原理使用validate注解原理 直接上干货&#xff0c;一行代码搞定校验&#xff1a; ValidateUtils.validat…...

ElasticSearch深入解析(六):集群核心配置

1.开发模式和生产模式 Elasticsearch默认运行在开发模式下&#xff0c;此模式允许节点在配置存在错误时照常启动&#xff0c;仅将警告信息写入日志文件。而生产模式则更为严格&#xff0c;一旦检测到配置错误&#xff0c;节点将无法启动&#xff0c;这是一种保障系统稳定性的安…...

Python 重构“策略”模式:用函数简化设计模式的实践

在软件设计中&#xff0c;设计模式是解决问题的通用模板。但随着编程语言特性的发展&#xff0c;某些经典模式可以通过更简洁的方式实现。本文以电商促销折扣场景为例&#xff0c;演示如何通过函数重构“策略”模式&#xff0c;减少代码量并提升可维护性。 经典策略模式实现 …...

​MCP协议深度解析:原理、应用与物联网时代的机遇-优雅草卓伊凡

MCP协议深度解析&#xff1a;原理、应用与物联网时代的机遇-优雅草卓伊凡 一、MCP协议技术详解 1.1 MCP协议的定义与起源 MCP&#xff08;Modbus Communication Protocol&#xff09;是一种基于主从架构的串行通信协议&#xff0c;最初由Modicon公司&#xff08;现为施耐德电…...

IOS 国际化词条 Python3 脚本

一、词条处理脚本---使用教程 (1)环境篇 1: 该脚本基于python3 环境&#xff0c;请确保你的mac 安装了python3 2: 包依赖&#xff0c;请在python3环境下安装 xlrd; pip3 install xlrd(2)使用篇 1: 桌面创建一个文件夹, 例如 wordEntry,将该脚本文件与下载的最新的 ’词条.xlsx‘…...

uniapp 支付宝小程序自定义 navbar 无效解决方案

如图&#xff1a; uniapp编译到支付宝小程序隐藏默认的导航栏失效了 解决方案&#xff1a; 在 pages.json 文件中找到 globalStyle 中加入以下代码&#xff1a; "mp-alipay": {"transparentTitle": "always","titlePenetrate":…...

uni-app - 微信小程序中,使用 navigateTo 传递非常大的数字传参精度丢失的问题

文章目录 🍉原因分析:JavaScript 数值精度限制🍉常用解决方法🍉代码示例🍉官方推荐与最佳实践🍉微信小程序环境注意事项🍉原因分析:JavaScript 数值精度限制 微信小程序(uni-app)中,参数是通过 URL 查询字符串传递的,其本质上仍由 JavaScript 进行处理。Jav…...

通信施工安全员B证适合哪些人考

通信施工安全员B证适合人群分析 一、适用岗位范围 通信工程施工人员 从事基站建设、光缆布放、管道施工等现场作业的技术工人 5G网络建设、室内分布系统安装等新型基础设施建设人员 项目管理岗位 通信工程项目经理、技术负责人 施工队长、班组长等现场管理人员 专职安全…...

vue3使用<el-date-picker分别设置开始时间和结束时间时,设置开始时间晚于当前时间,开始时间早于结束时间,结束时间晚于开始时间

vue3使用<el-date-picker分别设置开始时间和结束时间时&#xff0c;设置开始时间晚于当前时间&#xff0c;开始时间早于结束时间&#xff0c;结束时间晚于开始时间 为避免出现填写结束事件后再次修改开始时间&#xff0c;导致开始时间晚于结束时间&#xff0c;添加 change“…...

移远通信LG69T赋能零跑B10:高精度定位护航,共赴汽车智联未来

当前&#xff0c;汽车行业正以前所未有的速度迈向智能化时代&#xff0c;组合辅助驾驶技术已然成为车厂突出重围的关键所在。高精度定位技术作为实现车辆精准感知与高效协同的基石&#xff0c;其重要性日益凸显。 作为全球领先的物联网及车联网整体解决方案供应商&#xff0c;移…...

HTML应用指南:利用POST请求获取全国达美乐门店位置信息

达美乐比萨作为全球知名的披萨连锁品牌&#xff0c;自1960年创立以来&#xff0c;始终致力于为消费者提供高品质、快速配送的披萨体验。在中国市场&#xff0c;达美乐凭借其“30分钟必达”的承诺和经典美式风味&#xff0c;逐渐赢得了广大消费者的青睐。品牌通过不断拓展门店网…...

进程优先级以及切换调度

目录 进程优先级 基本概念 实操理解 优先级操作 竞争&#xff0c;独立&#xff0c;并行&#xff0c;并发 进程切换 寄存器 讲切换 linux进程调度算法 进程优先级 基本概念 cpu资源分配的先后顺序&#xff0c;就是指进程的优先权&#xff08;priority&#xff09;。优…...

揭开应用程序的神秘面纱:深入了解 AWS X-Ray

1.AWS X-Ray 概述&#xff1a; AWS X-Ray 是一项服务&#xff0c;它收集应用程序所处理请求的数据&#xff0c;并提供一些工具供您查看、筛选和深入了解这些数据&#xff0c;从而发现问题和优化机会。您不仅可以查看请求和响应的详细信息&#xff0c;还可以查看应用程序对下游…...

元宇宙2.0:当区块链成为数字世界的宪法

引言&#xff1a;当虚拟世界成为“新大陆” 清晨&#xff0c;你戴上VR设备进入一个由数字建筑构成的城市&#xff0c;这里的地皮属于全球玩家&#xff0c;街边的艺术品标着NFT认证码&#xff0c;咖啡馆里的人们用加密货币支付咖啡&#xff0c;而社区规则由持有代币的居民投票决…...

JVM调优实战(JVM Tuning Pactice)

JVM调优实战 JVM调优 JVM调优是指对Java虚拟机进行性能优化的实际应用。 JVM调优实战主要是通过优化JVM的内存管理、垃圾回收、线程管理、类加载、编译器等方面来提高Java应用程序的性能和稳定性。 JVM调优步骤 JVM调优实战通常需要经过以下步骤&#xff1a; 1.监控GC的状…...

网络原理 - 11(HTTP/HTTPS - 2 - 请求)

目录 HTTP 请求&#xff08;Request&#xff09; 认识 URL URL 基本格式 关于 URL encode 认识方法&#xff08;method&#xff09; 1. GET 方法 2. POST 方法 认识请求“报头”&#xff08;header&#xff09; Host Content-Length Content-Type User-Agent&…...

百度CarLife实现手机车机无缝互联

百度CarLife是百度推出的智能车联网解决方案&#xff0c;通过手机与车机互联技术&#xff0c;为用户提供安全便捷的车载互联网服务体验。 CarLife 实现手机与车机屏幕的无缝互联&#xff0c;让应用内容同步至车载系统&#xff0c;减少驾驶过程中操作手机的频率&#xff0c;提升…...

初识Redis · 缓存

目录 前言&#xff1a; 引入缓存 缓存更新策略 定期生成 实时生成 缓存注意事项 缓存预热 缓存穿透 缓存雪崩 缓存击穿 前言&#xff1a; 我们在Redis的学习中&#xff0c;逐渐了解到了Redis的用途是可以用来当作内存数据库&#xff0c;缓存&#xff0c;消息队列等&…...

Redis性能优化终极指南:从原理到实战的深度调优策略

一、内存优化&#xff1a;构建高效存储体系 1.1 三级过期键管理机制 Redis通过组合策略实现精准的内存回收&#xff1a; 定时删除&#xff08;主动淘汰&#xff09; 创建定时器在键到期时立即删除 优点&#xff1a;及时释放内存 缺点&#xff1a;高CPU消耗&#xff08;每个…...

哈希表笔记(一 )

设计思路 核心功能和 API 设计 (Core Functionality & API Design): 基本操作: 必须提供核心的 put(key, value)&#xff08;添加或更新键值对&#xff09;、get(key)&#xff08;根据键获取值&#xff09;、remove(key)&#xff08;根据键删除键值对&#xff09;、contain…...

c网络库libevent的http常用函数的使用(附带源码)

Libevent HTTP 核心函数详解与实战 核心概念HTTP 服务器端常用函数1. 初始化与绑定2. 设置请求处理回调3. 在回调函数中处理请求4. 发送响应5. 启动与停止6. 清理资源 HTTP 客户端常用函数1. 初始化2. 创建连接3. 创建并发送请求4. 在回调函数中处理响应5. 启动事件循环与清理 …...

java练习3

随机生成20个数字&#xff08;随机种子&#xff09; 分别使用冒泡排序、二叉树排序、插入排序进行排序 并输出最终结果以及三种排序使用的时间 package a01_第一次练习.a03_排序;import java.time.Duration; import java.time.LocalDateTime; import java.util.TreeSet;publi…...

当 AI 成为 “数字新物种”:人类职业的重构与进化

一、AI 的 “替代清单”&#xff1a;从流水线到办公室的全面侵袭 在深圳某智能工厂&#xff0c;机械臂正以 0.01 毫米的精度完成手机组装&#xff0c;100 台机器人 24 小时运转&#xff0c;替代了 3000 名工人。这种场景正在全球制造业蔓延 —— 麦肯锡预测&#xff0c;到 203…...

HarmonyOS ArkUI交互事件与手势处理全解析:从基础到高级实践

文章目录 一、交互事件1.1 通用事件1.1.1 事件分发1.1.1.1 触摸测试1. 触摸测试基本流程2. 触摸测试控制3. 自定义事件拦截4. 禁用控制5. 触摸热区设置6. 安全组件 1.1.1.2 事件响应链收集 1.1.2 触屏事件1.1.3 键鼠事件1.1.3.1 鼠标事件1.1.3.2 按键事件 1.1.4 焦点事件1.1.5 …...

【计算机网络】面试常考——GET 和 POST 的区别

GET 和 POST 的区别 GET 和 POST 是 HTTP 协议中最常用的两种请求方法&#xff0c;它们的主要区别体现在 用途、数据传输方式、安全性、缓存机制 等方面。以下是详细对比&#xff1a; 1. 用途 GET POST 主要用于 获取数据&#xff08;如查询、搜索&#xff09;。 主要用于 提…...

AI编程工具“幻觉”风险与飞算JavaAl的破局之道

近年来&#xff0c;AI编程辅助工具迅速崛起&#xff0c;极大地提升了开发者的工作效率。然而&#xff0c;这些工具普遍存在一个被称为“幻觉”(hallucination)的风险——AI可能会生成看似合理但实际错误、不安全或低效的代码。这种现象在复杂业务逻辑和特定领域开发中尤为明显&…...

【Python零基础入门系列】第1篇:Python 是什么?怎么装环境?推荐哪些 IDE?

各位网友们,欢迎来到我的 Python 学习专栏! 前两天看到新闻英伟达为 CUDA 添加原生 Python 支持,意味着开发者可直接用 Python 操作 GPU,加速 AI 和高性能计算,降低门槛,让 Python 的应用范围更广、能力更强。 一直想写一系列文章教知友们从零开始学会 Python 编程,目…...

VPN访问SAP组服务器报登陆负载均衡错误88:无法连接到消息服务器(RC=9)

用户反馈用SAPGUI接入SAP时报错&#xff1a;登陆负载均衡错误88&#xff1a;无法连接到消息服务器(RC9) 经了解是通过VPN访问&#xff0c;但VPN没有放行ICMP访问&#xff0c;导致不能PING通&#xff0c;不能确认是网络问题还是什么问题。 解决方案&#xff1a; 1、VPN由原&am…...

Linux查看程序端口占用情况

大家好&#xff0c;欢迎来到程序视点&#xff01;我是你们的老朋友.小二&#xff01; 核心问题&#xff1a; Tomcat 8080端口启动失败&#xff0c;提示端口被占用&#xff0c;但常规检查未发现Tomcat进程占用该端口。 关键排查步骤&#xff1a; 初步检查 使用 ps -aux | gre…...

[C]基础14.字符函数和字符串函数

博客主页&#xff1a;向不悔本篇专栏&#xff1a;[C]您的支持&#xff0c;是我的创作动力。 文章目录 0、总结1、字符分类、转换函数2、strlen的使用和模拟实现2.1 strlen的使用2.2 strlen的模拟实现 3、strcpy的使用和模拟实现3.1 strcpy的使用3.2 strcpy的模拟实现 4、strcat…...

三种机器学习类型

本文讲介绍三种机器学习类型&#xff1a;①监督学习&#xff0c;②无监督学习&#xff0c;③强化学习。我们主要了解监督学习和无监督学习即可。 下图介绍这三种机器学习类型的区别&#xff1a; 1 用来预测未来的监督学习 从有标签的训练数据中学习一个模型&#xff0c;用来…...

UE5 Set actor Location和 Set World Location 和 Set Relative Location 的区别

在 Unreal Engine 的蓝图里&#xff0c;SetRelativeLocation、SetWorldLocation 和 SetActorLocation 三个节点虽然都能改变物体位置&#xff0c;但作用对象和坐标空间&#xff08;Coordinate Space&#xff09;不同&#xff1a; 1. SetActorLocation 作用对象&#xff1a;整个…...

Glide 如何加载远程 Base64 图片

最近有个需求&#xff0c;后端给出的图片地址并不是正常的 URL&#xff0c;而且需要一个接口去请求&#xff0c;但是返回的是 base64 数据流。这里不关心为啥要这么多&#xff0c;原因有很多&#xff0c;可能是系统的问题&#xff0c;也可能是能力问题。当然作为我们 Android 程…...

JVM对象存储格式

引言 在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;对象的内存布局是一个重要的底层概念&#xff0c;它直接影响对象在内存中的存储方式和占用空间。了解对象存储格式不仅有助于优化程序性能&#xff0c;还能帮助我们更好地理解JVM的工作原理。本文将详细探讨对象存…...

3D Gaussian Splatting部分原理介绍和CUDA代码解读

本系列旨在帮助无CUDA代码经验的读者、以及3DGS的初学者理解代码逻辑。 3D GS论文原文链接&#xff1a;https://arxiv.org/abs/2308.04079 论文笔记链接&#xff1a;【论文笔记】3D Gaussian Splatting for Real-Time Radiance Field Rendering 【论文笔记】A Survey on 3D Ga…...

日本IT行业|salesforce开发语言占据的地位

在日本的IT行业中&#xff0c;Salesforce 开发语言处于一个较为专业但稳步增长的细分领域&#xff0c;并不是主流开发语言&#xff08;如 Java、Python、PHP&#xff09;&#xff0c;但其在某些行业和场景中地位越来越重要。 本篇以下是详细分析&#xff1a; Salesforce开发语言…...

1.1 点云数据获取方式——引言

图1-1-1点云建筑场景图 点云数据是指能够描述外部场景、对象表面的三维空间位置&#xff0c;并具有相关属性的点集&#xff0c;其每个离散点通常包括三维空间位置&#xff08;x,y,z&#xff09;以及强度、颜色等属性信息。大量分布的离散点集能够清晰而直接地描绘场景、对象的3…...

接入层架构演变

1、单体架构 请求过程 浏览器的请求通过 DNS Server 解析到指定的 IP 地址&#xff0c;浏览器通过 IP 地址访问 Web Server 缺点 当到达 Web Server 的性能瓶颈时&#xff08;瓶颈受到CPU&#xff0c;内存&#xff0c;io&#xff0c;带宽影响&#xff09;&#xff0c;无法进…...

python:sklearn 主成分分析(PCA)

参考书&#xff1a;《统计学习方法》第2版 第16章 主成分分析&#xff08;PCA&#xff09;示例 编写 test_pca_1.py 如下 # -*- coding: utf-8 -*- """ 主成分分析&#xff08;PCA&#xff09; """ import matplotlib.pyplot as plt from skl…...

力扣-数据结构-二叉树

94. 二叉树的中序遍历 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#x…...

嵌入式音视频实时通话EasyRTC打造设备安装与调试的高效远程解决方案

一、背景 在数字化浪潮席卷全球的今天&#xff0c;实时音视频通信技术已经成为众多领域不可或缺的重要组成部分。从智能家居到智能安防&#xff0c;从在线教育到远程医疗&#xff0c;人们对于高效、便捷、稳定且低延迟的音视频通信解决方案的需求日益迫切。而EasyRTC作为一款卓…...

AI 的未来是开源?DeepSeek 正在书写新篇章!

AI 的未来是开源&#xff1f;DeepSeek 正在书写新篇章&#xff01; 随着人工智能&#xff08;AI&#xff09;技术的迅猛发展&#xff0c;越来越多的企业和研究机构开始关注 AI 的开放性和透明度。开源不仅能够促进技术创新&#xff0c;还能加速知识的传播和应用。在这个背景下…...

抢先体验全新极小大模型Qwen3:0.6B

全民都在期待DeepSeek-R2的发布,但是一不小心被阿里截胡了,2025 年 4 月 29 日,阿里巴巴发布并开源了通义千问 Qwen3 系列大模型。据 大模型镜像网站 上关于Qwen3的介绍: Qwen3 是 Qwen 系列中最新一代的大型语言模型,提供一整套密集模型和混合专家 (MoE) 模型。Qwen3 基…...