[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] 示例…...

【ArcGIS Pro二次开发】(85):Aspose.Cells中的Excel操作
Aspose.Cells是一款功能强大的Excel文档处理和转换控件,开发人员和客户电脑无需安装Microsoft Excel也能在应用程序中实现类似Excel的强大数据管理功能。 1、获取工作薄Workbook string excelFile "C:\Users\Administrator\Desktop\FE.xlsx"; Workbook …...

基于java+springboot+vue实现的兴顺物流管理系统(文末源码+Lw)23-287
摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理,然而,随着近些年信息技术的迅猛发展,让许多比较老套的信息管理模式进行了更新迭代,货运信息因为其管理内容繁杂,管理数量繁多导致手工进行处理不能满足广…...

pytorch view、expand、transpose、permute、reshape、repeat、repeat_interleave
非contiguous操作 There are a few operations on Tensors in PyTorch that do not change the contents of a tensor, but change the way the data is organized. These operations include: narrow(), view(), expand() and transpose() permute() This is where the con…...

uni-app实现下拉刷新
业务逻辑如下: 1.在滚动容器中加入refresher-enabled属性,表示为开启下拉刷新 2.监听事件,添加refresherrefresh事件 3.在事件监听函数中加载数据 4.关闭动画,添加refresher-triggered属性,在数据请求前开启刷新动画…...

vue ts 应用梳理
文章目录 前言一、页面传值1.1 [props](https://cn.vuejs.org/guide/components/props.html)1.2 [emit](https://cn.vuejs.org/guide/components/events.html)1.3 [store](https://pinia.vuejs.org/zh/getting-started.html) 二、实时计算2.1 [watch](https://cn.vuejs.org/gui…...

CUDA12.4文档-全文翻译
本博客参考官方文档进行介绍,全网仅此一家进行中文翻译,走过路过不要错过。 官方网址:https://docs.nvidia.com/cuda/cuda-c-programming-guide/ 本文档分成多个博客进行介绍,在本人专栏中含有所有内容: https://blog.csdn.net/qq_33345365/category_12610860.html CU…...

【C 数据结构】循环链表
文章目录 【 1. 基本原理 】【 2. 循环链表的创建 】2.1 循环链表结点设计2.2 循环单链表初始化 【 3. 循环链表的 插入 】【 4. 循环单链表的 删除操作 】【 5. 循环单链表的遍历 】【 6. 实例 - 循环链表的 增删查改 】【 7. 双向循环链表 】 【 1. 基本原理 】 对于单链表以…...

Python列表
使用场景:列表是用来存储多组数据的 列表是可变类型 列表支持切片 1.基本规则 1.列表使用[]来表示 2.初始化列表:list [] 3.列表可以一次性存储多个数据:[数据1,数据2,数据3,…] 4.列表中的每一项&#…...

谈谈系列之金融直播展业畅想
近些年直播异常火热,对于各大中小型基金证券公司,也纷纷引入直播作为新型展业渠道。在这其中有一部分直接采用第三方云平台,也有少部分选择自建直播平台。当然自建直播平台也不是纯自研,大抵都是外购第三方厂商整体解决方案&#…...

【C 数据结构】双向链表
文章目录 【 1. 基本原理 】【 2. 双向链表的 创建 】实例 - 输出双向链表 【 3. 双向链表 添加节点 】【 4. 双向链表 删除节点 】【 5. 双向链表查找节点 】【 7. 双向链表更改节点 】【 8. 实例 - 双向链表的 增删查改 】 【 1. 基本原理 】 表中各节点中都只包含一个指针&…...