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

C++ 网络编程

1. socket

        Socket 是一种用于网络通信的编程接口,它提供了一种类似于文件描述符的接口,允许不同计算机之间的进程进行通信。Socket 可以工作在多种协议上,最常用的是 TCP/IP 和 UDP/IP 协议

1.1 UDP

1.1.1 概念

        UDP(用户数据报协议)是一种无连接的网络协议,它允许数据在不建立可靠连接的情况下快速传输。UDP 不保证数据的可靠性、顺序性或完整性,但它的速度比 TCP 快,适合对实时性要求较高的应用,例如视频流、语音通信、游戏等。

1.1.2 UDP 的特点

  1. 无连接:UDP 不需要建立连接,发送方可以直接发送数据报,接收方接收数据报。

  2. 不可靠:UDP 不保证数据报的传输顺序、完整性或可靠性。数据可能会丢失、重复或乱序到达。

  3. 轻量级:UDP 的头部只有8字节,比 TCP 的20-60字节的头部更轻量。

  4. 速度较快:由于没有连接建立和确认机制,UDP 的传输速度比 TCP 快。

1.1.3 UDP 数据报组成:

  1. UDP 头部(8字节):

    • 源端口(16位):发送方的端口号。

    • 目的端口(16位):接收方的端口号。

    • 长度(16位):UDP 数据报的总长度(包括头部和数据部分)。

    • 校验和(16位):用于检测数据报在传输过程中是否出错。

  2. 数据部分:用户数据。

1.1.4 示例代码

服务器代码:UDP 服务器会监听特定端口,接收来自客户端的消息并打印出来

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int sockfd;struct sockaddr_in server_addr, client_addr;socklen_t client_addr_len = sizeof(client_addr);char buffer[1024];// 创建 UDP 套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Error creating socket" << std::endl;return 1;}// 配置服务器地址server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080); // 监听端口server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口// 绑定套接字到地址if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {std::cerr << "Error binding socket" << std::endl;close(sockfd);return 1;}std::cout << "UDP server is running and waiting for messages..." << std::endl;while (true) {// 接收客户端消息int bytes_received = recvfrom(sockfd, buffer, sizeof(buffer), 0,(struct sockaddr*)&client_addr, &client_addr_len);if (bytes_received < 0) {std::cerr << "Error receiving message" << std::endl;continue;}buffer[bytes_received] = '\0'; // 确保字符串以 null 结尾std::cout << "Received message from client: " << buffer << std::endl;// 可选:向客户端发送响应const char* response = "Message received";sendto(sockfd, response, strlen(response), 0,(struct sockaddr*)&client_addr, client_addr_len);}close(sockfd);return 0;
}

客户端代码:UDP 客户端会向服务器发送消息,并接收服务器的响应。

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int sockfd;struct sockaddr_in server_addr;char buffer[1024];// 创建 UDP 套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {std::cerr << "Error creating socket" << std::endl;return 1;}// 配置服务器地址server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080); // 服务器端口server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 服务器 IP 地址std::cout << "Enter a message to send to the server: ";std::cin.getline(buffer, sizeof(buffer));// 发送消息到服务器if (sendto(sockfd, buffer, strlen(buffer), 0,(struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {std::cerr << "Error sending message" << std::endl;close(sockfd);return 1;}std::cout << "Waiting for server response..." << std::endl;// 接收服务器响应int bytes_received = recvfrom(sockfd, buffer, sizeof(buffer), 0,NULL, NULL);if (bytes_received < 0) {std::cerr << "Error receiving response" << std::endl;close(sockfd);return 1;}buffer[bytes_received] = '\0'; // 确保字符串以 null 结尾std::cout << "Server response: " << buffer << std::endl;close(sockfd);return 0;
}

基本逻辑

1.2 TCP 

1.2.1 概念 

        TCP(传输控制协议)是一种面向连接的、可靠的网络协议,用于在不可靠的网络中提供可靠的字节流服务。TCP 通过建立连接、确认机制、重传机制等技术,确保数据的完整性和顺序性,适用于对数据可靠性要求较高的应用,如文件传输、网页浏览、邮件服务等。

1.2.2 TCP 的特点

  1. 面向连接:TCP 在数据传输之前需要建立连接,确保通信双方的准备就绪。

  2. 可靠传输:TCP 提供可靠的数据传输服务,通过确认机制、重传机制和滑动窗口协议来确保数据的完整性和顺序性。

  3. 字节流:TCP 将数据视为字节流,不保留数据的边界信息。

  4. 流量控制:TCP 使用滑动窗口协议来控制发送方的发送速率,防止接收方被淹没。

  5. 拥塞控制:TCP 通过拥塞控制算法(如慢启动、拥塞避免、快速重传等)来避免网络拥塞。

1.2.3 示例代码

服务端

#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <unistd.h>int main() {int tcp_socket;int ret;// 1. 申请一个TCP的sockettcp_socket = socket(AF_INET, SOCK_STREAM, 0);if (tcp_socket == -1) {perror("socket");return -1;}int opt = 1;ret = setsockopt(tcp_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));if (ret < 0) {perror("set sock opt");return -1;}// 2. 作为服务器,应该在某一个端口上进行监测struct sockaddr_in self;memset(&self, 0, sizeof(self));// 2.1 填充socket tcp/ip协议的地址self.sin_family = AF_INET;self.sin_port = htons(7788);self.sin_addr.s_addr = htonl(INADDR_ANY);        // 服务器是可以在任何机器上运行,监测当前系统的所有IPret = bind(tcp_socket, (const struct sockaddr *) &self, sizeof(self));if (ret == -1) {perror("bind");return -1;}// 3. 将主动发送的socket变为被动监听的socket类型listen(tcp_socket, 5);printf("listen...\n");// 4. 等待新的客户端发来消息int new_fd;char buf[1024];ssize_t t;while (1) {// 4.1 使用accept等待listen fd是否有成功的描述new_fd = accept(tcp_socket, NULL, NULL);if (new_fd < 0) {perror("accept");break;}printf("New connection success!\n");// 5. 服务器等待新的客户端发来消息(请求),服务器根据请求来对客户端进行响应while (1) {		// 客户端发来消息,直到客户端关闭,服务器才关闭memset(buf, 0, sizeof(buf));// 5.1 接收请求t = recv(new_fd, buf, sizeof(buf), 0);if (t <= 0) {if (errno == 0) {printf("remote client closed!\n");break;}perror("recv");break;}buf[t] = 0;printf("receive : %s\n", buf);// 5.2 发送响应send(new_fd, "hello", 5, 0);}close(new_fd);}close(tcp_socket);return 0;
}

客户端

#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>int main(int argc, char *argv[]) {int tcp_socket;struct sockaddr_in dest;uint16_t port;socklen_t dest_len = sizeof(dest);int ret;if (argc < 3) {fprintf(stderr, "Usage: tcp_client ip port");exit(-1);}port = atoi(argv[2]);// 1. 申请一个TCP的sockettcp_socket = socket(AF_INET, SOCK_STREAM, 0);if (tcp_socket == -1) {perror("socket");return -1;}memset(&dest, 0, sizeof(dest));dest.sin_family = AF_INET;dest.sin_port = htons(port);dest.sin_addr.s_addr = inet_addr(argv[1]);		// inet_aton(argv[1], &dest.sin_addr);// 2. 第一次握手ret = connect(tcp_socket, (const struct sockaddr *)&dest, dest_len);if (ret < 0) {perror("connect");exit(-1);}printf("connect success!\n");// 3. 发起请求char buf[1024];memset(buf, 0, sizeof(buf));printf("<input>:");while (fgets(buf, sizeof(buf), stdin) != NULL) {buf[strlen(buf) - 1] = 0;if (strncmp(buf, "quit", 4) == 0) {break;}ret = send(tcp_socket, buf, strlen(buf), 0);if (ret == -1) {perror("send to");break;}printf("send %ld bytes success!\n", ret);ret = recv(tcp_socket, buf, sizeof(buf), 0);buf[ret] = 0;printf("server: %s\n", buf);printf("<input>:");}close(tcp_socket);return 0;
}

一个进程默认能打开1024个文件描述符

在C++中,多路I/O复用是一种高效的I/O处理方式,允许程序同时监视多个文件描述符(如网络连接或文件),并等待它们中的任何一个变为可读或可写。以下是几种常见的多路I/O复用技术及其在C++中的实现方式;

2. 多路IO复用

2.1 select

2.1.1 概念

select 是一种多路I/O复用技术,用于同时监视多个文件描述符(如套接字、文件等),以确定它们是否准备好进行读、写或异常操作。

select 使用位域来表示文件描述符集合,通过位操作来快速检查和更新文件描述符的状态。内核只维护这个位域结构。

 工作流程
select 的工作流程可以分为以下几个步骤:
初始化文件描述符集合:将需要监视的文件描述符添加到 fd_set 中。
调用 select:将文件描述符集合传递给 select 函数,同时指定最大文件描述符值(fdmax)和超时时间。
等待 I/O 事件:select 函数会阻塞,直到:
至少有一个文件描述符准备好进行 I/O 操作。
超时时间到达。
检查结果:select 返回后,程序可以检查哪些文件描述符已经准备好,然后进行相应的读写操作。

1.2 函数原型及参数说明

#include <sys/select.h>int select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, struct timeval* timeout);nfds
表示要监视的最大文件描述符加1。例如,如果你的文件描述符范围是0到10,nfds 应该是11。
这个参数用于指定 select 需要检查的最大文件描述符范围。
readfds
指向一个 fd_set 类型的指针,表示需要监视的可读文件描述符集合。
如果不需要监视可读文件描述符,可以传入 NULL。
writefds
指向一个 fd_set 类型的指针,表示需要监视的可写文件描述符集合。
如果不需要监视可写文件描述符,可以传入 NULL。
exceptfds
指向一个 fd_set 类型的指针,表示需要监视的异常条件文件描述符集合。
如果不需要监视异常条件,可以传入 NULL。
timeout
指向一个 struct timeval 类型的指针,表示 select 的超时时间。
如果传入 NULL,select 将会阻塞,直到有文件描述符准备好。
如果传入一个时间值,select 将在指定时间内未检测到任何准备好状态时返回。

1.3 示例代码

#include <iostream>
#include <cstring>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int server_fd, client_fd;struct sockaddr_in address;int addrlen = sizeof(address);fd_set readfds;struct timeval tv;// 创建 Socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// 绑定地址和端口address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8080);if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 监听连接if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}std::cout << "Server is running on port 8080..." << std::endl;// 初始化文件描述符集合FD_ZERO(&readfds);FD_SET(server_fd, &readfds);// 设置超时时间tv.tv_sec = 5;  // 5 秒超时tv.tv_usec = 0;int max_fd = server_fd;while (true) {fd_set tempfds = readfds; // 复制文件描述符集合int activity = select(max_fd + 1, &tempfds, NULL, NULL, &tv);if ((activity < 0) && (errno != EINTR)) {std::cout << "Select error";}// 判断服务器的监听套接字是否有新的连接请求。if (FD_ISSET(server_fd, &tempfds)) {if ((client_fd = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {perror("accept failed");exit(EXIT_FAILURE);}std::cout << "Client connected." << std::endl;FD_SET(client_fd, &readfds); // 将客户端文件描述符加入集合if (client_fd > max_fd) {max_fd = client_fd; // 更新最大文件描述符}}// 检查客户端文件描述符是否准备好for (int i = 0; i <= max_fd; i++) {if (FD_ISSET(i, &tempfds)) {if (i == server_fd) {continue; // 跳过服务器端口}char buffer[1024] = {0};int valread = recv(i, buffer, 1024, 0);if (valread <= 0) {std::cout << "Client disconnected." << std::endl;close(i); // 关闭客户端连接FD_CLR(i, &readfds); // 从集合中移除} else {std::cout << "Message from client: " << buffer << std::endl;send(i, buffer, strlen(buffer), 0); // 回显消息}}}}close(server_fd);return 0;
}

2.2 epoll(只支持linux)

2.2.1 概述

epollepoll 是 Linux 内核提供的一种高效的 I/O 多路复用机制。epoll 的核心在于它将文件描述符的管理与事件通知分离,通过内核维护一个事件表来高效地处理 I/O 事件。适用于需要长时间保持连接的场景,如 Web 服务器。

epoll 的工作原理基于以下三个核心系统调用:
epoll_create:
创建一个 epoll 实例,返回一个特殊的文件描述符(epfd),用于后续操作。
内部使用红黑树存储所有监听的文件描述符(FD),并维护一个就绪链表用于存储活跃事件。
epoll_ctl:
用于管理红黑树中的文件描述符,支持添加(EPOLL_CTL_ADD)、修改(EPOLL_CTL_MOD)和删除(EPOLL_CTL_DEL)操作。
每个文件描述符与一个回调函数绑定,当事件发生时,内核会将事件插入到就绪链表中。
epoll_wait:
等待就绪链表中的事件发生。如果有事件,直接返回给用户态,时间复杂度为 O(1);如果没有事件,根据超时参数阻塞或立即返回Epoll 的高效数据结构
红黑树(RB-Tree):
存储所有监听的文件描述符,支持高效的插入、删除和查找操作(时间复杂度为 O(log N)),适用于海量连接。
就绪链表(Ready List):
存储活跃事件,内核通过回调函数将事件加入链表,epoll_wait 只需遍历此链表即可,避免了全量扫描。

2.2.2 优势

相比 selectpollepoll 的优势在于:

  • 更高的效率epoll 不需要每次调用时都遍历所有文件描述符,而是只处理就绪的文件描述符。

  • 无文件描述符数量限制epoll 不受 FD_SETSIZE 的限制,可以处理大量并发连接。

  • 事件驱动epoll 是被动触发的,只有当文件描述符状态发生变化时,内核才会通知用户空间

2.2.3 工作模式

2.2.4 epoll 与 select/poll 的比较

特性selectpollepoll
文件描述符限制有限(默认 1024)无限制无限制
效率随文件描述符数量增加而降低随文件描述符数量增加而降低高效,不受文件描述符数量影响
事件通知轮询轮询事件驱动
跨平台性跨平台跨平台Linux 特有
应用场景小规模并发、实时性要求高中等规模并发高并发、长连接
 Epoll 的性能优势
无需遍历全部 FD:epoll_wait 只处理就绪链表中的事件,时间复杂度为 O(1),而 select 和 poll 的时间复杂度为 O(n)。
减少内存拷贝:通过 mmap 共享内核与用户空间内存,避免了 select 和 poll 的多次数据拷贝。
支持海量连接:红黑树结构使 epoll 可管理数十万级文件描述符,适用于现代高并发服务器。

2.2.5 示例代码

#include <iostream>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int server_fd, epoll_fd;struct sockaddr_in address;int addrlen = sizeof(address);struct epoll_event event, events[10];// 创建 TCP 套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("socket failed");return -1;}// 绑定地址和端口address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8080);if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {perror("bind failed");return -1;}// 监听连接if (listen(server_fd, 3) < 0) {perror("listen failed");return -1;}// 创建 epoll 实例epoll_fd = epoll_create(1);if (epoll_fd < 0) {perror("epoll_create failed");return -1;}// 将监听套接字加入 epollevent.data.fd = server_fd;event.events = EPOLLIN | EPOLLET; // 边缘触发if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {perror("epoll_ctl failed");return -1;}std::cout << "Server is running on port 8080..." << std::endl;while (true) {int nfds = epoll_wait(epoll_fd, events, 10, -1);for (int n = 0; n < nfds; ++n) {if (events[n].data.fd == server_fd) {// 接受新连接int client_fd = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);if (client_fd < 0) {perror("accept failed");continue;}// 将客户端套接字加入 epollevent.data.fd = client_fd;event.events = EPOLLIN | EPOLLET; // 边缘触发epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);} else {// 处理客户端数据char buffer[1024] = {0};int valread = read(events[n].data.fd, buffer, sizeof(buffer));if (valread <= 0) {close(events[n].data.fd);} else {std::cout << "Message from client: " << buffer << std::endl;write(events[n].data.fd, buffer, valread);}}}}close(server_fd);close(epoll_fd);return 0;
}

3. 长连接与短连接

在网络编程中,长连接短连接是两种常见的连接模式,它们的区别主要在于连接的持续时间和使用场景。

3.1 长连接

        长连接是指客户端和服务器之间建立的连接在较长时间内保持打开状态,而不是在一次数据传输后立即关闭。这种连接模式适用于需要频繁交互的场景。

3.1.1 特点
  1. 持续时间长:连接在较长时间内保持打开状态,避免了频繁建立和关闭连接的开销。

  2. 高效:减少了连接建立和关闭的开销,适合高频率的数据交互。

  3. 资源占用:由于连接保持打开状态,会占用一定的系统资源(如文件描述符、内存等)。

  4. 适用场景:适用于需要实时交互的应用,如聊天应用、游戏服务器、WebSockets 等。

3.1.2 示例
  • WebSockets:用于实时通信,客户端和服务器之间保持一个持久的连接,数据可以随时发送。

  • 游戏服务器:客户端和服务器之间需要频繁交互,长连接可以减少延迟。

  • 即时通讯:如微信、QQ 等,客户端和服务器之间保持长连接,以便实时接收消息。

3.2 短连接

短连接是指客户端和服务器之间的连接在一次数据传输后立即关闭。这种连接模式适用于偶尔交互的场景。

3.2.1 特点

  1. 连接时间短:每次交互后立即关闭连接,避免了长时间占用资源。

  2. 资源占用少:由于连接时间短,系统资源占用较少。

  3. 开销较大:每次交互都需要建立和关闭连接,增加了连接的开销。

  4. 适用场景:适用于偶尔交互的应用,如传统的 HTTP 请求。

3.2.2 示例

  • HTTP/1.0:每次请求后关闭连接,适合简单的网页浏览。

  • 文件下载:客户端请求文件后,下载完成后关闭连接。

相关文章:

C++ 网络编程

1. socket Socket 是一种用于网络通信的编程接口&#xff0c;它提供了一种类似于文件描述符的接口&#xff0c;允许不同计算机之间的进程进行通信。Socket 可以工作在多种协议上&#xff0c;最常用的是 TCP/IP 和 UDP/IP 协议 1.1 UDP 1.1.1 概念 UDP&#xff08;用户数据报协…...

SQL-leetcode—1683. 无效的推文

1683. 无效的推文 表&#xff1a;Tweets ----------------------- | Column Name | Type | ----------------------- | tweet_id | int | | content | varchar | ----------------------- 在 SQL 中&#xff0c;tweet_id 是这个表的主键。 content 只包含美式键盘上的字符&am…...

vue前端可视化大屏页面适配方案

参考了其他博主的代码&#xff0c;但发现会有滚动条&#xff0c;并且居中的位置不太对&#xff0c;所以改了一下css&#xff0c;修复了这些问题&#xff0c;直接上代码 <template> <div class"ScaleBoxA"><divclass"ScaleBox"ref"Sca…...

mars3d接入到uniapp的时候ios上所有地图的瓦片都无法加载解决方案

用的是【Mars3d】官网的uniapp的仓库&#xff0c;安卓没有问题&#xff0c;但是ios的不行 相关链接 mars3d-uni-app: uni-app技术栈下的Mars3D项目模板 解决方案&#xff1a;感觉所有图片请求全被拦截了 uniapp的ios内核不允许跨域&#xff0c;需要先把瓦片下载后转base64&…...

Dockfile语法

目录 dockerfile的作用 1. 构建 Docker 映像 2. 提高开发和运维效率 3. 版本控制 4. 提供可移植性和灵活性 使用示例 总结 dockerfile应该放的位置 为什么放在根目录&#xff1f; 例外情况 调用构建 dockerfile的基本结构和常用指令 基本结构和常用指令 示例 Dock…...

Nginx负载均衡

一。Nginx负载均衡的算法以及过程 二。nginx四层负载均衡的配置&#xff08;四层&#xff09; 1.vi /etc/nginx/conf.d/lb.conf 比较常见&#xff1a;weight&#xff1a;设置权重&#xff0c;backup&#xff1a;当其他主机全部用不了&#xff0c;这个作为备份 2.systemctl r…...

【C】初阶数据结构5 -- 栈

前面学习了两种最基本的数据结构 -- 顺序表和链表&#xff0c;接下来就可以基于这两种数据结构来实现其他数据结构了。其实&#xff0c;其他的数据结构的物理结构要么是数组&#xff0c;要么就是链表&#xff0c;所以学好顺序表和链表是学好其他数据结构的基础。接下里&#xf…...

Linux查找占用的端口,并杀死进程的简单方法

在Linux系统管理中&#xff0c;识别并管理占用特定端口的进程是一项常见且重要的任务。以下是优化过的步骤指南&#xff0c;帮助您高效地完成这一操作&#xff0c;同时提供了一个简洁的命令参考表。 Linux下识别并终止占用端口的进程 1. 探寻端口占用者 使用 lsof命令 lsof…...

为什么Pytorch中实例化模型会直接调用forward方法?

在 PyTorch 中&#xff0c;为何定义一个继承自 nn.Module 的自定义类并实现 forward 方法后&#xff0c;直接调用模型实例时&#xff0c;便会自动调用其 forward 方法&#xff1f;例如使用 output model(x) 这种形式。 因为自定义的神经网络类所继承的 nn.Module 类对 __call_…...

easyexcel快速使用

1.easyexcel EasyExcel是一个基于ava的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel 即通过java完成对excel的读写操作&#xff0c; 上传下载 2.easyexcel写操作 把java类中的对象写入到excel表格中 步骤 1.引入依赖 <depen…...

DeepSeek的出现会对百度有多大影响?

当DeepSeek与ChatGPT等大模型接管搜索入口&#xff0c;我们正见证百年一遇的信息革命。 01 传统搜索已死&#xff1f;AI助手正在重写游戏规则&#xff01; 当DeepSeek与ChatGPT等大模型接管搜索入口&#xff0c;我们正见证百年一遇的信息革命。 就像汽车淘汰马车、触屏终结按键…...

生成格雷码

以下是Verilog实现格雷码的两种常见方法&#xff1a; 1. 二进制转格雷码&#xff08;组合逻辑实现&#xff09; module binary_to_gray #(parameter N 4 // 默认4位位宽 )(input [N-1:0] binary, // 二进制输入output [N-1:0] gray // 格雷码输出 );assign gray binary…...

【STM32】BootLoader和IAP详解

文章目录 0 前言1 基本概念2 BootLoader3 主程序相关配置4 相关理论&#xff1a;芯片启动与中断响应5 特殊情况&#xff1a;Cortex-M0内核的芯片 0 前言 最近在研究一个RT-Thread的项目&#xff0c;遇到很多之前没咋遇见过的STM32相关的知识&#xff0c;想着顺带也整体过一遍。…...

Threadlocal的实现原理

文章目录 ThreadLocal与Thread关系分析Threadlocal 不支持继承性lnheritableThreadLocal 类 ThreadLocal与Thread关系分析 由该图可知&#xff0c; Thread 类中有一个 threadLocals 和一个 inheritableThreadLocals &#xff0c; 它们 都是 ThreadLocalMap 类型 的变量 &#x…...

【Elasticsearch】多字段查询方式汇总

在 Elasticsearch 中&#xff0c;实现多字段查询的常见方式有以下几种&#xff0c;每种方式适用于不同的场景&#xff1a; --- ### 1. **multi_match 查询** - **用途**&#xff1a;在多个字段中执行同一查询&#xff0c;支持多种匹配策略。 - **关键参数**&#xff1a…...

Unity使用反射进行Protobuf(CS/SC)协议,json格式

protobuf生成的协议,有挺多协议的.利用反射生成dto进行伪协议的响应 和 发送请求 应用场景: 请求(CS)_后端先写完了,前端还搞完时,可使用此请求,可自测 响应(SC)_可自行构建一个响应,对数据进行测试 // 请求 使用物品 CS message ReqUseItem{optional Opcodes MessageID1[def…...

MySQL和SQL server的区别

在当今数据驱动的世界里&#xff0c;数据库技术的选择对于企业和个人开发者来说至关重要。MySQL 和 SQL Server 是两个广泛使用的数据库管理系统&#xff08;DBMS&#xff09;&#xff0c;它们各自拥有独特的优势和适用场景。本文将深入探讨这两个数据库系统之间的区别&#xf…...

SpringMVC请求执行流程源码解析

文章目录 0.SpringMVC九大内置组件1.processRequest方法1.请求先到service方法2.然后不管是get还是post都会跳转到processRequest方法统一处理 2.doService方法3.doDispatch方法1.代码2.checkMultipart 4.核心流程 0.SpringMVC九大内置组件 1.processRequest方法 1.请求先到se…...

LabVIEW与小众设备集成

在LabVIEW开发中&#xff0c;当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求&#xff0c;而厂家虽然提供了配套软件&#xff0c;但由于系统中还需要控制其他设备且不能使用厂商的软件时&#xff0c;必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中&#xff0…...

docker-compose暴露端口,但其他主机无法访问问题。

问题描述&#xff1a;docker-compose暴露端口&#xff0c;但其他主机无法访问问题。 排障思路&#xff1a; 执行命令&#xff1a;ss -antlp | grep 80&#xff0c;发现端口正常监听0.0.0.0:80&#xff08;ps&#xff1a;如果是127.0.0.1:80则只能本机访问同区域网段服务器执行…...

【MySQL】 基本查询(上)

欢迎拜访&#xff1a;雾里看山-CSDN博客 本篇主题&#xff1a;【MySQL】 基本查询(上) 发布时间&#xff1a;2025.2.14 隶属专栏&#xff1a;MySQL CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 目录 Create基…...

python 爬虫教程 0 基础入门 一份较为全面的爬虫python学习方向

文章目录 前言一、Python 爬虫简介二、环境搭建1. 下载 Python2. 安装 Python3. 安装必要的库 三、一个简单的爬虫示例四、应对网站反爬机制五、深入学习方向 前言 以下是一份较为全面的 Python 爬虫教程&#xff0c;涵盖基础知识、环境搭建、简单示例、反爬应对及深入学习方向…...

总结:使用JDK原生HttpsURLConnection,封装HttpsUtil工具类,加载自定义证书验证,忽略ssl证书验证

总结&#xff1a;使用JDK原生HttpsURLConnection&#xff0c;封装HttpsUtil工具类&#xff0c;加载自定义证书验证&#xff0c;忽略ssl证书验证 一HttpsUtil工具类二SSLUtil工具类 一HttpsUtil工具类 package com.example.util;import javax.net.ssl.HttpsURLConnection; impo…...

你认为如何理解“约定大于配置”?

SpringBoot的“约定大于配置”&#xff08;Convention Over Configuration&#xff09;是一种核心理念&#xff0c;旨在简化开发过程&#xff0c;减少开发人员在配置上的繁琐工作。以下是对其含义的详细介绍&#xff1a; 一、定义与目的 定义&#xff1a;约定优于配置&#x…...

Linux 基础IO——重定向和缓冲区

目录 一、重定向 1、重定向的本质 2、使用 dup2 系统调用 &#xff08;1&#xff09;输出重定向 &#xff08;2&#xff09;追加重定向 (3) 输入重定向 ​ 二、缓冲区 1.理解缓冲区 2.缓冲区刷新问题 3.为什么要有缓冲区&#xff1f; 4.这个缓冲区在哪里&#xff…...

基于若依开发的工程项目管系统开源免费,用于工程项目投标、进度及成本管理的OA 办公开源系统,非常出色!

一、简介 今天给大家推荐一个基于 RuoYi-Flowable-Plus 框架二次开发的开源工程项目管理系统&#xff0c;专为工程项目的投标管理、项目进度控制、成本管理以及 OA 办公需求设计。 该项目结合了 Spring Boot、Mybatis、Vue 和 ElementUI 等技术栈&#xff0c;提供了丰富的功能…...

华为云之CodeArts IDE的使用体验

一、CodeArts IDE介绍 1.1 CodeArts IDE简介 CodeArts IDE定位华为云开发者桌面&#xff0c;是利用华为自研IDE内核技术&#xff0c;面向华为云开发者提供的智能化可扩展桌面集成开发环境&#xff08;IDE&#xff09;&#xff0c;结合华为云行业和产业开发套件&#xff0c;实现…...

DeepSeek-VL2 环境配置与使用指南

DeepSeek-VL2 环境配置与使用指南 DeepSeek-VL2 是由 DeepSeek 公司开发的一种高性能视觉-语言模型&#xff08;VLM&#xff09;。它是 DeepSeek 系列多模态模型中的一个版本&#xff0c;专注于提升图像和文本之间的交互能力。 本文将详细介绍如何配置 DeepSeek-VL2 的运行环…...

超纯水设备的智能化控制系统为用户带来安全简便的操作体验

随着信息技术的发展&#xff0c;智能化已经成为工业装备的重要发展方向之一。超纯水设备在这方面也走在了前列&#xff0c;配备了高性能的PLC控制系统及人机交互界面&#xff0c;实现了全方位的智能监控和自动化操作。本文将重点介绍该设备的智能化控制系统&#xff0c;探讨它如…...

若依系统环境搭建记录

开源若依系统网上资料也很全的&#xff0c;本篇博文记录下自己搭建环境过程中遇到的一些问题。 配置Maven和编辑器选择 我懒得配置Eclipse了&#xff0c;直接用vscode作为编辑器&#xff0c;后面构建运行都用命令行。 配置数据库连接 按照mysql5.7按网上教程即可&#xff1…...

基于Docker-compose的禅道部署实践:自建MySQL与Redis集成及故障排查指南

基于Docker-compose的禅道部署实践&#xff1a;自建MySQL与Redis集成及故障排查指南 禅道镜像版本&#xff1a;easysoft/zentao:21.4 Redis版本&#xff1a;redis:6.2.0 Mysql版本&#xff1a;mysql:8.0.35 文章目录 **基于Docker-compose的禅道部署实践&#xff1a;自建MySQL与…...

为AI聊天工具添加一个知识系统 之102 详细设计之43 自性三藏 之3 祖传代码

本文要点 法宝和三藏 总括如下&#xff1a; 三藏[经/律/论] 法宝&#xff1a;法阵/法轮/法力&#xff08;三“件” 证件 / 表件 / 物件 &#xff0c;分别对应三藏&#xff1a;论藏/律藏/经藏 --反序&#xff09;。“法宝”演示了 发轮轮转的法阵中物件具有的法力。 这里的“…...

fork: retry: No child processes-linux18

根据错误信息 fork: retry: Resource temporarily unavailable 和 sh: fork: retry: No child processes&#xff0c;这通常是因为系统资源不足&#xff08;例如可用的进程数、内存或 CPU 限制&#xff09;导致的。为了解决这个问题&#xff0c;您可以尝试以下几种方法&#xf…...

渗透测试--文件包含漏洞

文件包含漏洞 前言 《Web安全实战》系列集合了WEB类常见的各种漏洞&#xff0c;笔者根据自己在Web安全领域中学习和工作的经验&#xff0c;对漏洞原理和漏洞利用面进行了总结分析&#xff0c;致力于漏洞准确性、丰富性&#xff0c;希望对WEB安全工作者、WEB安全学习者能有所帮助…...

【物联网】电子电路基础知识

文章目录 一、基本元器件1. 电阻2. 电容3. 电感4. 二极管(1)符号(2)特性(3)实例分析5. 三极管(1)符号(2)开关特性(3)实例6. MOS管(产效应管)(1)符号(2)MOS管极性判定(3)MOS管作为开关(4)MOS管vs三极管7. 门电路(1)与门(2)或门(3)非门二、常用元器件…...

vue学习10

1.GPT和Copilot Copilot Tab接受 删除键&#xff0c;不接受 ctrlenter更多方案 更适合的是修改方向 const submitForm async () > {//等待校验结果await formRef.value.validate()//提交修改await userUpdateInfoService(form.value)//通知user模块&#xff0c;进行数据更…...

【C语言】C语言 停车场管理系统的设计与实现(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 系列文章目录 目录 系列文章目录一、设计要求二、设…...

LeetCodehot100 力扣热题100 二叉树展开为链表

代码思路 目标&#xff1a; 将二叉树展平&#xff08;flatten&#xff09;为一个单链表。展平后的链表应该按照前序遍历的顺序排列节点&#xff0c;即&#xff1a; • 节点的左子树指针设置为 nullptr。 • 节点的右子树指针指向下一个节点。 代码注释及思路 class Solution…...

备战蓝桥杯 Day1 回顾语言基础

开启蓝桥杯刷题之路 Day1 回顾语言基础 1.配置dev 工具->编译选项->勾选编译时加入以下命令->设定编译器配置(release和debug)都要-> -stdc11 ->代码生成/优化->代码生成/优化->语言标准(-std)->ISO C11 ->代码警告->显示最多警告信息(-Wall)…...

基于Ceedling的嵌入式软件单元测试

Ceedling 如果你使用 Ceedling&#xff08;一个针对 C 代码单元测试的构建管理器&#xff09;&#xff0c;可以更方便地管理测试。Ceedling 会自动处理 Unity 和 CMock 的集成&#xff0c;无需手动编写 Makefile。 1.环境搭建 1.1 Ruby环境 sudo apt-get install ruby1.2 安…...

聊一聊FutureTask源码中体现的“自旋锁”思想

前言 这篇文章记录了笔者自己对FutureTask的部分源码设计的思考与心得&#xff0c;属于笔者自己的观点&#xff0c;若有哪位热爱源码研究的同仁觉得我说的不对&#xff0c;欢迎批评指正。 提示&#xff1a;在阅读之前必须对FutureTask的源码和实现原理有一定的了解。本文要聊…...

自有证书的rancher集群使用rke部署k8s集群异常

rancher使用自签域名&#xff0c;或者商业证书容易踩到的坑。 最开始的报错&#xff1a; docker logs kubelet‘s id E0214 13:04:14.590268 9614 pod_workers.go:1300] "Error syncing pod, skipping" err"failed to \"StartContainer\" for …...

LabVIEW外腔二极管激光器稳频实验

本项目利用LabVIEW软件开发了一个用于外腔二极管激光器稳频实验的系统。系统能够实现激光器频率的稳定控制和实时监测&#xff0c;为激光实验提供了重要支持。 项目背景&#xff1a; 系统解决了外腔二极管激光器频率不稳定的问题&#xff0c;以满足对激光器频率稳定性要求较高…...

使用docker compose启动postgres并设置时区

设置PostGres时区 方法 1: 使用 POSTGRES_INITDB_ARGS 设置时区方法 2: 使用初始化脚本设置时区创建 init-user-db.sql更新 docker-compose.yml 启动服务 要在启动 PostgreSQL 数据库时设置时区&#xff0c;可以通过在 docker-compose.yml 文件中添加环境变量或通过配置文件来实…...

杜绝遛狗不牵绳,AI技术助力智慧城市宠物管理

在我们的生活中&#xff0c;宠物扮演着越来越重要的角色。然而&#xff0c;随着养宠人数的增加&#xff0c;一系列问题也随之而来&#xff0c;如烈性犬伤人、遛狗不牵绳、流浪犬泛滥等。这些问题不仅影响了社会秩序&#xff0c;也给宠物本身带来了安全隐患。幸运的是&#xff0…...

【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第二十节】

ISO 14229-1:2023 UDS诊断服务测试用例全解析&#xff08;WriteMemoryByAddress_0x3D服务&#xff09; 作者&#xff1a;车端域控测试工程师 更新日期&#xff1a;2025年02月14日 关键词&#xff1a;UDS协议、0x3D服务、内存写入、ISO 14229-1:2023、ECU测试 一、服务功能概述…...

[npm install 报错] Verion 9 of Highlight.js has reached EOL

1、在项目中执行npm install 报错 Verion 9 of Highlight.js has reached EOL,如下图: 2、报错原因 Highlight.js 不再支持10以前的版本&#xff0c;需下载10及之后的版本 3、解决办法 打开项目中的package.json文件&#xff0c;将highlight.js的版本修改为:10.7.2,删除node…...

Flutter Gradle 命令式插件正式移除,你迁移旧版 Gradle 配置了吗?

在 Flutter 3.29 版本里官方正式移除了 Flutter Gradle Apply 插件&#xff0c;其实该插件自 3.19 起已被弃用&#xff0c;同时 Flutter 团队后续也打算把 Flutter Gradle 从 Groovy 转换为 Kotlin&#xff0c;并将其迁移到使用 AGP&#xff08;Android Gradle Plugin&#xff…...

CCF-GESP 等级考试 2024年9月认证C++二级真题解析

2024年9月真题 一、单选题&#xff08;每题2分&#xff0c;共30分&#xff09; 正确答案&#xff1a;A 考察知识点&#xff1a;计算机存储 解析&#xff1a;磁心存储元件是早期计算机中用于存储数据的部件&#xff0c;它和现代计算机中的内存功能类似&#xff0c;都是用于临时…...

CubeMX配置STM32L071KZT6

明确需要配置的项 下面是工作中遇到某个项目提炼出来的的功能需求。其中MCU选用STM32L071KZT6。 名称 标识 IO功能 对应引脚 备注 蜂鸣器 BUZZER 开关量输出 PA2 指示灯 LED-R PA15 LED-G PA12 LED-Y PA11 按键 KEY-1 开关量输入 PB5 外…...