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:每次请求后关闭连接,适合简单的网页浏览。

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C/C++内存管理

目录 前言 1、C/C内存划分 2、C语言中的动态内存管理方式 3、C内存管理方式 3.1操作内置类型 3.2操作自定义类型 3.3为什么对应的new和delete必须搭配使用&#xff08;了解&#xff09; 4、operator new与operator delete函数 5、new和delete的实现原理 5.1内置类型 5…

微软开源GraphRAG的使用教程-使用自定义数据测试GraphRAG

微软在今年4月份的时候提出了GraphRAG的概念&#xff0c;然后在上周开源了GraphRAG,Github链接见https://github.com/microsoft/graphrag,截止当前&#xff0c;已有6900Star。 安装教程 官方推荐使用Python3.10-3.12版本&#xff0c;我使用Python3.10版本安装时&#xff0c;在…

RK3568平台开发系列讲解(调试篇)网卡队列均衡负载

🚀返回专栏总目录 文章目录 一、RPS 的介绍1. RPS 的工作原理2. RPS 配置3. 启用和调优 RPS4. RPS 优势二、下行测试iperf测试沉淀、分享、成长,让自己和他人都能有所收获!😄 RPS(Receive Packet Steering) 是一种用于提高网络接收性能的技术,通常用于多核处理器系统中…

RagFlow + Docker Desktop + Ollama + DeepSeek-R1本地部署自己的本地AI大模型工具

前期准备 首先&#xff0c;我们需要下载 Ollama 以及配置相关环境。 Ollama 的 GitHub仓库 &#xff08;https://github.com/ollama/ollama&#xff09;中提供了详细的说明&#xff0c;简单总结如下: Step1&#xff1a;下载 Ollama 下载&#xff08;https://ollama.com/dow…

变分边界详解

起因 当时看VAE论文时有这么一段&#xff0c;但是看完直接一头雾水&#xff0c;这都那跟哪&#xff0c;第一个公式咋做的变换就变出那么一堆。网上搜了很多博客都语焉不详&#xff0c;只好自己来写一篇&#xff0c;希望能解答后来人的疑惑。 公式1 参考文章&#xff1a;证据…

云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维

如今&#xff0c;消息队列已成为分布式架构中不可或缺的关键服务&#xff0c;为电商、物联网、游戏和教育等行业&#xff0c;提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年&#xff0c;我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;面向…

【蓝桥杯嵌入式】8_IIC通信-eeprom读写

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 1、电路图 这个电路允许通过I2C总线与EEPROM(M24C02-WMN6TP)和数字电位器(MCP4017T-104ELT)进行通信。EEPROM用于存储数据&#xff0c;而数字电位器可以用…

DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件

1 DeepSeek处理自有业务的案例&#xff1a;让AI给你写一份小众编辑器(EverEdit)的语法着色文件 1.1 背景 AI能力再强&#xff0c;如果不能在企业的自有业务上产生助益&#xff0c;那基本也是一无是处。将企业的自有业务上传到线上训练&#xff0c;那是脑子进水的做法&#xff…

Java常用设计模式面试题总结(内容详细,简单易懂)

设计模式的分类 创建型模式&#xff1a;通过隐藏对象创建的细节&#xff0c;避免直接使用 new 关键字实例化对象&#xff0c;从而使程序在判断和创建对象时更具灵活性。常见的模式包括&#xff1a; 工厂模式抽象工厂模式单例模式建造者模式原型模式 结构型模式&#xff1a;通…

使用HX搭建UNI-APP云开发项目(适合新手小白与想学云开发的宝子)

什么是uni-app云开发 uni-app云开发是uni-app提供的一套后端服务,它可以帮助开发者快速搭建起一个完整的后端服务,包括数据库、云函数、存储等。开发者只需要关注前端页面的开发,后端服务由uni-app云开发提供。 uni-app云开发的优势: 快速搭建后端服务:uni-app云开发提供了…

零基础学CocosCreator·第九季-网络游戏同步策略与ESC架构

课程里的版本好像是1.9&#xff0c;目前使用版本为3.8.3 开始~ 目录 状态同步帧同步帧同步客户端帧同步服务端ECS框架概念ECS的解释ECS的特点EntityComponentSystemWorld ECS实现逻辑帧&渲染帧 ECS框架使用帧同步&ECS 状态同步 一般游戏的同步策略有两种&#xff1a;…

最新版Edge浏览器集成ActiveX控件之金山WpsDocFrame控件

背景 WpsDocFrame控件‌是由金山公司开发的ActiveX控件&#xff0c;主要用于OA系统中&#xff0c;支持在浏览器中嵌入WPS文档的查看和编辑功能。 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有…

Win10系统IP地址修改_出现了一个意外的情况不能完成所有你在设置中所要求的更改---Windows工作笔记001

今天在修改win10系统中的ip地址的时候报错了 来看看如何解决吧,挺简单,简单记录一下 这个时候就需要使用cmd命令来修改 一定要使用,管理员权限,运行cmd才可以 然后首先: 输入 netsh 然后输入 ip 然后输入: set address "以太网" 172.19.126.199 255.255.255.0…

算法 ST表

目录 前言 一&#xff0c;暴力法 二&#xff0c;打表法 三&#xff0c;ST表 四&#xff0c;ST表的代码实现 总结 前言 ST表的主要作用是在一个区间里面寻找最大值&#xff0c;具有快速查找的功能&#xff0c;此表有些难&#xff0c;读者可以借助我的文章和网上的课程结…

node.js+兰空图床实现随机图

之前博客一直用的公共的随机图API&#xff0c;虽然图片的质量都挺不错的&#xff0c;但是稳定性都比较一般&#xff0c;遂打算使用之前部署的兰空图床&#xff0c;自己弄一个随机图 本文章服务器操作基于雨云——新一代云服务提供商的云服务器进行操作&#xff0c;有兴趣的话可…

CNN|ResNet-50

导入数据 import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号import os,PIL,pathlib import numpy as npfrom tensorflow import keras from tensor…

基于微型5G网关的石化厂区巡检机器人应用

石化工业属于高风险产业&#xff0c;由于涉及易燃易爆、有毒有害工业原料&#xff0c;为了保障企业的安全生产与持续运营&#xff0c;因此相比其它行业需要进行更高频次、更全面细致的安全巡检和监测。由于传统的人工巡检监测存在诸多不便&#xff0c;例如工作强度大、现场环境…

Docker+Jenkins自动化部署SpringBoot项目【详解git,jdk,maven,ssh配置等各种配置,附有示例+代码】

文章目录 DockerJenkins部署SpringBoot项目一.准备工作1.1安装jdk111.2安装Maven 二.Docker安装Jenkins2.1安装Docker2.2 安装Jenkins2.3进入jenkins 三.Jenkins设置3.1安装jenkins插件3.2全局工具配置全局配置jdk全局配置maven全局配置git 3.3 系统配置安装 Publish Over SSH …

知识图谱数据库 Neo4j in Docker笔记

下载 docker pull neo4j:community官方说明 https://neo4j.com/docs/operations-manual/2025.01/docker/introduction/ 启动 docker run \--restart always \--publish7474:7474 --publish7687:7687 \--env NEO4J_AUTHneo4j/your_password \--volumeD:\files\knowledgegrap…

前缀和算法篇:解决子数组累加和问题

1.前缀和原理 那么在介绍前缀和的原理之前&#xff0c;那么我们先来说下前缀和最基本的一个应用场景&#xff0c;那么就是如我们标题所说的子数组累加和问题&#xff0c;那么假设我们现在有一个区间为[L,R]的数组&#xff0c;那么我们要求的其中子数组比如[L,i]或者[i,m] (L&l…