[C++/Linux] 网络I/O处理
引言:网络数据能够正常到达用户并且被接收是进行网络传输的根本目的,网络传输的数据发送和接收有多种方案,本文章就对通过向量接收和发送等数据传输方式,并且对多种I/O模型进详细分析介绍。
目录
一.I/O函数
1.1 recv和send
recv函数
send函数
1.2 readv和writev函数
readv函数
writev函数
1.3 recvmsg和recvmsg函数
recvmsg函数
sendmsg函数
1.4 客户—服务器实例
服务器端代码:
客户端代码:
二.I/O模型介绍
2.1 阻塞I/O(Blocking I/O)
2.2非阻塞I/O(Non-blocking I/O)
2.3I/O多路复用(I/O Multiplexing)
2.4信号驱动I/O(Signal-driven I/O)
2.5异步I/O(Asynchronous I/O)
三.监视函数
3.1select和pselect
select函数
pselect函数
3.2poll函数和ppoll函数
poll函数
ppoll函数
四.总结
一.I/O函数
1.1 recv和send
在网络编程中,recv 和 send 函数是用于在套接字上进行数据传输的两个基本函数。它们是在Unix-like系统中的Berkeley套接字 API(也称为BSD套接字API)的一部分,在Windows系统中也有对应的实现。
recv函数
recv 函数用于从连接的套接字接收数据。函数原型如下:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
-
sockfd:指定接收数据的套接字文件描述符。 -
buf:指向缓冲区的指针,用于存放接收到的数据。 -
len:指定缓冲区的大小,即最多接收的数据量。 -
flags:指定接收数据的操作方式,可以是0或者以下一个或多个值的逻辑或:MSG_OOB:接收带外数据(Out-of-Band Data)。MSG_PEEK:查看数据但不从接收队列中移除数据。MSG_WAITALL:等待所有请求的数据,直到请求的数量被接收为止。- 等等。
返回值:
- 成功时,返回接收到的字节数。
- 如果连接被对方关闭,返回0。
- 出错时,返回-1,并设置errno来指示错误。
send函数
send 函数用于向连接的套接字发送数据。函数原型如下:
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
参数说明:
-
sockfd:指定发送数据的套接字文件描述符。 -
buf:指向要发送数据的指针。 -
len:指定要发送数据的长度。 -
flags:指定发送数据的操作方式,可以是0或者以下一个或多个值的逻辑或:MSG_OOB:发送带外数据。MSG_DONTROUTE:发送数据时不通过网关。- 等等。
返回值:
- 成功时,返回发送的字节数。
- 出错时,返回-1,并设置errno来指示错误。
1.2 readv和writev函数
readv 和 writev 函数是 Unix 和类 Unix 操作系统中的系统调用,它们允许程序在一次操作中从多个缓冲区读取数据或将数据写入多个缓冲区。这些函数对于分散读(scatter read)和集中写(gather write)操作非常有用。
readv函数
readv 函数用于从文件描述符读取数据到多个缓冲区中。函数原型如下:
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
参数说明:
fd:指定要读取数据的文件描述符。iov:指向iovec结构数组的指针,每个iovec结构指定一个缓冲区。iovcnt:指定iov数组中iovec结构的数量。
iovec 结构定义如下:
struct iovec {void *iov_base; /* Starting address */size_t iov_len; /* Number of bytes to transfer */
};
iov_base:指向数据缓冲区的指针。iov_len:指定缓冲区的长度。
返回值:
- 成功时,返回读取的总字节数。
- 如果遇到文件结束,返回0。
- 出错时,返回-1,并设置errno来指示错误。
writev函数
writev 函数用于将多个缓冲区的数据写入到文件描述符。函数原型如下:
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
参数说明:
fd:指定要写入数据的文件描述符。iov:指向iovec结构数组的指针,每个iovec结构指定一个数据源缓冲区。iovcnt:指定iov数组中iovec结构的数量。
返回值:
- 成功时,返回写入的总字节数。
- 出错时,返回-1,并设置errno来指示错误。
1.3 recvmsg和recvmsg函数
recvmsg 和 sendmsg 函数是 Unix 和类 Unix 操作系统中的系统调用,它们提供了比 recv 和 send 更高级的接口,用于在套接字上发送和接收数据。这些函数支持更多的功能,如scatter/gather I/O、控制消息的发送和接收,以及带外数据。
recvmsg函数
recvmsg 函数用于从套接字接收数据,并可以接收辅助数据(ancillary data)。函数原型如下:
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
参数说明:
-
sockfd:指定接收数据的套接字文件描述符。 -
msg:指向msghdr结构的指针,该结构包含了接收操作的所有参数。 -
flags:指定接收数据的操作方式,可以是0或者以下一个或多个值的逻辑或:MSG_OOB:接收带外数据。MSG_PEEK:查看数据但不从接收队列中移除数据。MSG_WAITALL:等待所有请求的数据,直到请求的数量被接收为止。- 等等。
msghdr 结构定义如下:
struct msghdr {void *msg_name; /* Optional address */socklen_t msg_namelen; /* Size of address */struct iovec *msg_iov; /* Scatter/gather array */int msg_iovlen; /* # elements in msg_iov */void *msg_control; /* Ancillary data, see below */socklen_t msg_controllen; /* Ancillary data buffer len */int msg_flags; /* Flags on received message */
};
msg_name和msg_namelen:用于接收对方地址信息(仅用于面向连接的套接字)。msg_iov和msg_iovlen:指定分散读的缓冲区数组iovec和其长度。msg_control和msg_controllen:用于接收辅助数据和控制信息。msg_flags:接收消息的标志,由系统填充。
返回值:
- 成功时,返回接收到的字节数。
- 如果连接被对方关闭,返回0。
- 出错时,返回-1,并设置errno来指示错误。
sendmsg函数
sendmsg 函数用于向套接字发送数据,并可以发送辅助数据。函数原型如下:
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
参数说明:
-
sockfd:指定发送数据的套接字文件描述符。 -
msg:指向msghdr结构的指针,该结构包含了发送操作的所有参数。 -
flags:指定发送数据的操作方式,可以是0或者以下一个或多个值的逻辑或:MSG_OOB:发送带外数据。MSG_DONTROUTE:发送数据时不通过网关。- 等等。
返回值:
- 成功时,返回发送的字节数。
- 出错时,返回-1,并设置errno来指示错误。
1.4 客户—服务器实例
这个服务器的功能主要是返回客户端输入的数据长度,其中使用了I/O函数中的readv和writev。
服务器端代码:
(我这个代码涉及到许多前面的基础知识,需要了解的就可以看我上一篇博客:
写文章-CSDN创作中心socket套接字函数-CSDN博客写文章-CSDN创作中心)
#include<t_stdio.h>
#include<t_file.h>
#include<stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include<unistd.h>
static struct iovec*vs=NULL;
void sig_process(int signo){//信号处理函数printf("catch a exit signal..\n");free(vs);_exit(0);
}#define port 8888//端口号
#define backlog 2//最大监听数量//业务处理逻辑
void process_conn_server(int s){char buffer [30];ssize_t size=0; //向量的缓冲区//申请3个向量空间struct iovec * v = (struct iovec *)malloc(3*sizeof(struct iovec));if(!v) E_MSG("malloc",-1);vs = v;//挂接全局变量,易于释放管理v[0].iov_base= buffer;//每个向量十个地址空间v[1].iov_base= buffer+10;v[2].iov_base= buffer+20;v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;//初始化长度为10for(;;){size = readv(s, v , 3);// 从套接字中读取数据放入数据缓冲区if(size == 0){return ;}//构建响应字符sprintf(v[0].iov_base,"%d",size);sprintf(v[1].iov_base,"bytes alter");sprintf(v[2].iov_base,"ogether\n");//设置写入数据的长度v[0].iov_len = strlen(v[0].iov_base);v[1].iov_len = strlen(v[1].iov_base);v[2].iov_len = strlen(v[2].iov_base);writev(s , v , 3);//发送给客户端}}
int main(int argc ,char * argv[])
{int ss ,sc;//服务器和客户端的套接字文件描述符struct sockaddr_in server_addr;//服务器地址结构struct sockaddr_in client_addr;//客户端地址结构pid_t pid;//创建子进程进行分叉进行signal(SIGINT,sig_process);//添加sigint信号到信号掩码signal(SIGPIPE,sig_process);ss = socket(AF_INET,SOCK_STREAM,0);// 创建服务器套接字if(ss < 0) E_MSG("socket",-1);bzero(&server_addr,sizeof(server_addr));//将地址清零server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);//本地地址server_addr.sin_port=htons(port);//设置端口//绑定本地到套接字符int err = bind(ss,(struct sockaddr * )&server_addr,sizeof(server_addr));if(err < 0)E_MSG("bind",-1);err = listen(ss,backlog);//创建监听队列for(;;){int addrlen = sizeof(struct sockaddr);sc = accept(ss,(struct sockaddr * )&client_addr,&addrlen);//获取用户套接字if(sc < 0)continue;//客户端出错,结束这次循环,继续监听客户;pid = fork();//创建新的子进程来处理当前连接客户端;if(pid==0){close(ss);// 子进程中关闭服务端process_conn_server(sc);}else {close(sc);//父进程关闭客户端连接,继续监听;}}return 0;
}
客户端代码:
#include<t_stdio.h>
#include<t_file.h>
#include<stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include<unistd.h>
#define port 8888
static int s;
static struct iovec*vc=NULL;
void sig_proccess(int signo){printf("catch a exit signal..\n");free(vc);_exit(0);
}void sig_pipe(int signo){printf("catch a sigpipe signal..\n");free(vc);_exit(0);}//业务处理函数
void process_conn_client(int s){char buffer [30];ssize_t size=0; //向量的缓冲区//申请3个向量空间struct iovec * v = (struct iovec *)malloc(3*sizeof(struct iovec));if(!v) E_MSG("malloc",-1);vc = v;//挂接全局变量,易于释放管理v[0].iov_base= buffer;//每个向量十个地址空间v[1].iov_base= buffer+10;v[2].iov_base= buffer+20;v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;//初始化长度为10int i=0;for(;;){//从标准输入中读取数据放入缓冲区buffer中size = read(0,v[0].iov_base,10);//只有十个字节if(size>0){v[0].iov_len = size;writev(s,v,1);//发送给服务器v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;size=readv(s,v,3);//从服务器读取数据for(i = 0;i<3;i++){if(v[i].iov_len > 0){write(1,v[i].iov_base,v[i].iov_len);//将服务区处理后数据输出}} }}}
int main(int argc ,char * argv[])
{struct sockaddr_in server_addr;//服务器结构地址int err;if(argc == 1){printf("pls input server addr\n");return 0;}//没有输入指令参数signal(SIGINT,sig_proccess);signal(SIGPIPE,sig_pipe);//设置信号掩码s = socket(AF_INET,SOCK_STREAM,0);//创建客户端套接字if(s < 0)E_MSG("socket",-1);//设置服务器地址bzero(&server_addr,sizeof(server_addr));//将地址清0server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = htons(INADDR_ANY);//本地地址server_addr.sin_port=htons(port);//设置端口inet_pton(AF_INET,argv[1],&server_addr.sin_addr);//将用户输入的字符串ip转化为二进制ipconnect(s,(struct sockaddr *)&server_addr,sizeof(server_addr));//连接服务器process_conn_client(s);return 0;
}
对于这两个代码,大家可以仔细阅读,我写了非常详细的注释,包括信号的处理,业务逻辑的处理等等,可以将我们整个基础网络知识串联起来!
二.I/O模型介绍
网络编程中的I/O模型主要影响程序如何处理网络套接字的读写操作。以下是几种常见的I/O模型:
2.1 阻塞I/O(Blocking I/O)
阻塞I/O模型是最简单的I/O模型。当发起一个I/O操作(如读或写)时,如果数据未准备好,程序会阻塞直到操作完成。在这段时间内,程序无法执行其他任务。
// 阻塞读
char buffer[1024];
read(socket, buffer, sizeof(buffer));
2.2非阻塞I/O(Non-blocking I/O)
在非阻塞I/O模型中,I/O操作不会阻塞程序。如果数据未准备好,I/O操作会立即返回一个错误码(通常是EAGAIN或EWOULDBLOCK)。程序需要定期轮询检查数据是否准备好.
// 设置套接字为非阻塞模式
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);// 非阻塞读
char buffer[1024];
while (read(socket, buffer, sizeof(buffer)) == -1 && errno == EAGAIN) {// 数据未准备好,继续做其他事情
}
2.3I/O多路复用(I/O Multiplexing)
I/O多路复用允许程序同时监视多个文件描述符,等待一个或多个变得“就绪”。这可以通过select、poll、epoll(Linux特有)或kqueue(BSD特有)系统调用来实现。
// 使用select进行I/O多路复用
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(socket, &readfds);select(socket + 1, &readfds, NULL, NULL, NULL);if (FD_ISSET(socket, &readfds)) {char buffer[1024];read(socket, buffer, sizeof(buffer));
}
2.4信号驱动I/O(Signal-driven I/O)
信号驱动I/O模型中,程序通过sigaction系统调用请求内核在文件描述符就绪时发送一个信号。当数据准备好时,内核会发送一个SIGIO信号,程序可以在信号处理函数中处理数据。
// 设置信号处理函数
struct sigaction sa;
sa.sa_handler = io_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGIO, &sa, NULL);// 设置套接字的所有者
fcntl(socket, F_SETOWN, getpid());// 开启信号驱动I/O
int flags = fcntl(socket, F_GETFL, 0);
fcntl(socket, F_SETFL, flags | O_ASYNC);
2.5异步I/O(Asynchronous I/O)
异步I/O模型中,程序发起I/O操作后,立即返回,无需等待数据准备好。当操作完成时,程序会收到通知。这种模型通常通过aio_read、aio_write等系统调用来实现。
// 异步读
aiocb aio;
memset(&aio, 0, sizeof(aio));
aio.aio_fildes = socket;
aio.aio_buf = buffer;
aio.aio_nbytes = sizeof(buffer);
aio.aio_offset = 0;aio_read(&aio);
每种I/O模型都有其适用的场景。例如,阻塞I/O适用于简单应用,非阻塞I/O和I/O多路复用适用于需要处理多个套接字的应用,而异步I/O适用于需要高性能和低延迟的应用。在选择合适的I/O模型时,需要考虑应用的特定需求和性能。
三.监视函数
3.1select和pselect
在网络编程中,select 和 pselect 函数是用于多路复用(I/O multiplexing)的系统调用,它们允许程序同时监视多个文件描述符,以判断它们是否准备好进行读、写或异常(错误)操作。
select函数
select 函数的原型如下:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数说明:
nfds:需要检查的最高文件描述符加1。通常设置为最大的文件描述符加上1。readfds:指向一组文件描述符的指针,这些文件描述符需要检查是否准备好读取数据。writefds:指向一组文件描述符的指针,这些文件描述符需要检查是否准备好写入数据。exceptfds:指向一组文件描述符的指针,这些文件描述符需要检查是否发生异常。timeout:指向timeval结构的指针,用于指定select应该阻塞等待的最大时间。如果设置为NULL,select将无限期地等待;如果设置为0,select将立即返回。
timeval 结构定义如下:
struct timeval {long tv_sec; /* seconds */long tv_usec; /* microseconds */
};
返回值:
- 成功时,返回准备好的文件描述符的数量。
- 如果超时,返回0。
- 出错时,返回-1,并设置errno来指示错误。
使用 select 时,需要使用 FD_ZERO、FD_SET 和 FD_CLR 宏来操作 fd_set 集合。
pselect函数
pselect 函数与 select 类似,但它提供了一些额外的功能,特别是在处理信号方面。pselect 的原型如下:
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
参数说明:
- 前四个参数与
select函数相同。 timeout:指向timespec结构的指针,用于指定pselect应该阻塞等待的最大时间。timespec结构与timeval类似,但它使用秒和纳秒来表示时间。sigmask:指向sigset_t类型的一个信号集的指针,用于在pselect调用期间临时替换进程的信号掩码。这意味着pselect在等待文件描述符就绪时会阻塞指定的信号。
timespec 结构定义如下:
struct timespec {time_t tv_sec; /* seconds */long tv_nsec; /* nanoseconds */
};
返回值:
- 成功时,返回准备好的文件描述符的数量。
- 如果超时,返回0。
- 出错时,返回-1,并设置errno来指示错误。
例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>int main() {fd_set readfds;struct timeval timeout;int result;FD_ZERO(&readfds);FD_SET(0, &readfds); // 监视标准输入(文件描述符0)timeout.tv_sec = 5; // 设置超时时间为5秒timeout.tv_usec = 0;result = select(1, &readfds, NULL, NULL, &timeout);if (result == -1) {perror("select");exit(EXIT_FAILURE);} else if (result > 0) {printf("Data is available to read.\n");} else {printf("Timeout occurred.\n");}return 0;
}
在这个例子中,我们使用 select 来监视标准输入(文件描述符0),设置超时时间为5秒。如果在这段时间内有数据可读,select 将返回大于0的值;如果超时,将返回0;如果发生错误,将返回-1。
3.2poll函数和ppoll函数
poll 和 ppoll 函数是 Unix 和类 Unix 操作系统中的系统调用,用于多路复用(I/O multiplexing),允许程序同时监视多个文件描述符的读写状态。与 select 和 pselect 函数相比,poll 和 ppoll 提供了更丰富的接口和更好的性能。
poll函数
poll 函数的原型如下:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数说明:
fds:指向一个pollfd结构数组的指针,每个结构描述了一个要监视的文件描述符。nfds:指定fds数组中pollfd结构的数量。timeout:指定poll应该阻塞等待的最大时间(毫秒)。如果设置为-1,poll将无限期地等待;如果设置为0,poll将立即返回。
pollfd 结构定义如下:
struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */
};
fd:要监视的文件描述符。events:请求监视的 events(通过位掩码指定)。revents:返回时,表示实际发生的事件(通过位掩码指定)。
events 和 revents 可以是以下标志的组合(定义在 <poll.h> 头文件中):
POLLIN:有数据可读。POLLOUT:可以写数据。POLLERR:发生错误。POLLHUP:挂起。POLLNVAL:无效的请求。
返回值:
- 成功时,返回准备好的文件描述符的数量。
- 如果超时,返回0。
- 出错时,返回-1,并设置errno来指示错误。
ppoll函数
ppoll 函数与 poll 类似,但它提供了一些额外的功能,特别是在处理信号方面。ppoll 的原型如下:
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask);
参数说明:
- 前三个参数与
poll函数相同。 timeout:指向timespec结构的指针,用于指定ppoll应该阻塞等待的最大时间。timespec结构与timeval类似,但它使用秒和纳秒来表示时间。sigmask:指向sigset_t类型的一个信号集的指针,用于在ppoll调用期间临时替换进程的信号掩码。这意味着ppoll在等待文件描述符就绪时会阻塞指定的信号。
返回值:
- 成功时,返回准备好的文件描述符的数量。
- 如果超时,返回0。
- 出错时,返回-1,并设置errno来指示错误。
例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>int main() {struct pollfd fds[1];int result;fds[0].fd = 0; // 监视标准输入(文件描述符0)fds[0].events = POLLIN; // 监视可读事件result = poll(fds, 1, 5000); // 设置超时时间为5000毫秒if (result == -1) {perror("poll");exit(EXIT_FAILURE);} else if (result > 0) {if (fds[0].revents & POLLIN) {printf("Data is available to read.\n");}} else {printf("Timeout occurred.\n");}return 0;
}
在这个例子中,我们使用 poll 来监视标准输入(文件描述符0),设置超时时间为5000毫秒。如果在这段时间内有数据可读,poll 将返回大于0的值;如果超时,将返回0;如果发生错误,将返回-1。
四.总结
这篇文章对数据I/O进行了整体的介绍,包括recv ,send, readv , writev,recmsg , sendmsg等I/O函数,并且给了很多例子,来介绍I/O的各种模型及其使用,相信经过这篇文章的学习,大家对网络编程中的I/O操作能有个整体认知!!!
相关文章:
[C++/Linux] 网络I/O处理
引言:网络数据能够正常到达用户并且被接收是进行网络传输的根本目的,网络传输的数据发送和接收有多种方案,本文章就对通过向量接收和发送等数据传输方式,并且对多种I/O模型进详细分析介绍。 目录 一.I/O函数 1.1 recv和send rec…...
HarmonyOS4 页面路由
Index.ets: import router from ohos.routerclass RouterInfo {// 页面路径url: string// 页面标题title: stringconstructor(url: string, title: string) {this.url urlthis.title title} }Entry // 入口組件 Component struct Index {State message: string 页面列表// …...
ShardingSphere再回首
概念: 连接:通过协议 方言及库存储的适配,连接数据和应用,关注多模数据苦之间的合作 增量:抓取库入口流量题提供重定向, 流量变形(加密脱敏)/鉴权/治理(熔断限流)/分析等 可插拔:微内核 DDL:cr…...
第七篇:3.6 其他评估考虑/4.审计指南/5. 通用报告规范/6.披露指南、参考标准及其他 - IAB/MRC及《增强现实广告效果测量指南1.0》
翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之- 3.1 广告印象(AD Impression)第三篇广告效果测量定义和其他矩阵之- 3.2 可见性 (Viewability)第四篇 …...
函数、指针和数组的相互运用(C语言)
1、函数指针数组 含义:数组的每个元素都是函数指针类型.eg: (此代码链接:http://t.csdnimg.cn/ClJmb.也可以在我发布博客中找到) 2、指向函数指针数组的指针 1、引入 3、回调函数 1、含义:就是一个通过…...
.Net Core/.Net 6/.Net 8,一个简易的消息队列
.Net Core/.Net 6/.Net 8,一个简易的消息队列 身份验证接口身份验证接口实现program.cs通过api调用 做着玩的, 只实现了消息入队出队功能,没有持久化,也没有其它任何高级功能 直接上代码 public class AMQBase//:ISingleton {/// <summary…...
OpenHarmony4.0分布式任务调度浅析
1 概述 OpenHarmony 分布式任务调度是一种基于分布式软总线、分布式数据管理、分布式 Profile 等技术特性的任务调度方式。它通过构建一种统一的分布式服务管理机制,包括服务发现、同步、注册和调用等环节,实现了对跨设备的应用进行远程启动、远程调用、…...
element-ui backtop 组件源码分享
今日简单分享 backtop 组件的源码实现,从以下三个方面: 1、backtop 组件页面结构 2、backtop 组件属性 3、backtop 组件事件 一、backtop 组件页面结构 二、backtop 组件属性 2.1 target 属性,触发滚动的对象,类型 string&am…...
MongoDB快照(LVM)业务场景应用实战
MongoDB和LVM快照概述 MongoDB的重要性:MongoDB支持的灵活的文档模型,使其成为处理大量分散数据的理想选择,特别是在需要快速迭代和频繁更改数据结构的应用中。 LVM(逻辑卷管理)快照技术基本概念:LVM允许…...
3D开发工具HOOPS:推动汽车行业CAD可视化发展
在最近的行业对话中,Tech Soft 3D(HOOPS厂商)的Jonathan Girroir和Actify的Peter West探讨了CAD可视化在当代企业中的重要性和挑战。作为CAD可视化领域的佼佼者,Actify通过其广受欢迎的Spinfire应用,赋能了全球40多个国…...
Centos安装MySQL提示公钥尚未安装
一、问题 在Centos7.9使用yum安装MySQL时出现错误,提示:mysql-community-server-5.7.44-1.el7.x86_64.rpm 的公钥尚未安装,如下图所示: 执行命令:systemctl start mysqld也提示错误:Failed to start mysq…...
FebHost:英国.UK域名简介
.UK域名是互联网上最广为人知且广泛使用的国家代码顶级域名之一。作为英国官方的国家代码,自诞生之日起,.UK域名对英国本土个人、企业及在线品牌建设扮演了关键角色。 .UK域名于1985年首次推出,这是早期为创建有序域名系统而努力的一部分。当…...
SQL Serve---查询
概要 1、order by子句 —默认asc(升序)、desc(降序) 2、distinct关键字 3、group by子句 4、聚合函数 —max()、min()、sum()、avg()、count() 5、having子句 6、compute子句 英文关键字 order by 排序 asc…...
RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tags
RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs 文章目录 RabbitMQ3.13.x之十一_RabbitMQ中修改用户密码及角色tgs1. 修改用户的密码1. 修改密码语法2. 修改案例 2.修改角色tags1. 修改标签(tags)语法2. 修改案例 可以使用 RabbitMQ 的命令行工具 rabbitmqctl 来修改用…...
Taro打包生成不同目录
使用taro init创建taro项目时,taro默认打包目录是: /config/index.js outputRoot:dist默认的目录,编译不同平台代码时就会覆盖掉,为了达到多端同步调试的目的,这时需要修改默认生成目录了,通过查看官方文…...
2024-04-08 NO.5 Quest3 手势追踪进行 UI 交互
文章目录 1 玩家配置2 物体配置3 添加视觉效果4 添加文字5 其他操作5.1 双面渲染5.2 替换图片 在开始操作前,我们导入先前配置好的预制体 MyOVRCameraRig,相关介绍在 《2024-04-03 NO.4 Quest3 手势追踪抓取物体-CSDN博客》 文章中。 1 玩家配置 &a…...
PaddleDetection 项目使用说明
PaddleDetection 项目使用说明 PaddleDetection 项目使用说明数据集处理相关模块环境搭建 PaddleDetection 项目使用说明 https://github.com/PaddlePaddle/PaddleDetection/blob/release/2.7/configs/ppyoloe/README_cn.md 自己项目: https://download.csdn.net/d…...
leetcode解题思路分析(一百五十五)1352 - 1358 题
最后 K 个数的乘积 请你实现一个「数字乘积类」ProductOfNumbers,要求支持下述两种方法: add(int num) 将数字 num 添加到当前数字列表的最后面。 getProduct(int k) 返回当前数字列表中,最后 k 个数字的乘积。 你可以假设当前列表中始终 至少…...
如何将普通maven项目转为maven-web项目
文件-项目结构(File-->Project Structure ) 模块-->learn(moudle-->learn) 选中需要添加web的moudle,点击加号,我得是learn,单击选中后进行下如图操作: 编辑路径 结果如下…...
LeetCode 226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1] 示例 2: 输入:root [2,1,3] 输出:[2,3,1] 示例…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...
