嵌入式学习第二十七天!(TCP并发模型)

TCP并发模型:

1. TCP多线程模型:

    缺点:创建线程会带来资源开销,能够实现的并发量比较有限。

2. IO模型:

    1. 阻塞IO:

        没有数据到来时,可以让任务挂起,节省CPU资源开销,提高系统效率

    2. 非阻塞IO:

        程序未接收到数据时一直执行,效率很低

        举例应用:

write.c

#include "head.h"int main(void)
{int fd = 0;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_WRONLY);if(fd == -1){perror("fail to open");return -1;}while(1){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);write(fd, tmpbuff, strlen(tmpbuff));}close(fd);return 0;
}

        后面的举例应用的write.c都为上面所示

read.c

#include "head.h"int main(void)
{int fd = 0;int flags = 0;ssize_t nsize = 0;char *pret = NULL;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}flags = fcntl(fd, F_GETFL);flags |= O_NONBLOCK;fcntl(fd, F_SETFL, flags);flags = fcntl(0, F_GETFL);flags |= O_NONBLOCK;fcntl(0, F_SETFL, flags);while(1){memset(tmpbuff, 0, sizeof(tmpbuff));pret = gets(tmpbuff);if(pret != NULL){printf("STDIN:%s\n", tmpbuff);}memset(tmpbuff, 0, sizeof(tmpbuff));nsize = read(fd, tmpbuff, sizeof(tmpbuff));if(nsize > 0){printf("RECV:%s\n", tmpbuff);}}close(fd);return 0;
}

        通过fcntl将fd和stdin文件描述符设置为非阻塞IO,所以read.c既可以通过管道接收消息,也可以同终端输入,接收消息,二者不会堵塞。

    3. 异步IO:

        只能绑定一个文件描述符用来读取数据

        举例应用:

read.c

#include "head.h"int fd = 0;void handler(int signo)
{char tmpbuff[1024] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = read(fd, tmpbuff, sizeof(tmpbuff));if(nsize > 0){printf("RECV:%s\n", tmpbuff);}return;}int main(void)
{int flags = 0;ssize_t nsize = 0;char *pret = NULL;char tmpbuff[1024] = {0};signal(SIGIO, handler);mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}flags = fcntl(fd, F_GETFL);flags |= O_ASYNC;fcntl(fd, F_SETFL, flags);fcntl(fd, F_SETOWN, getpid());while(1){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}close(fd);return 0;
}

    4. 多路复用:

        1. select:

            1. select监听的集合中的文件描述符有上限限制

            2. select有内核层向用户层数据空间拷贝的过程,占用系统资源开销

                原因:在使用select函数时,会涉及到内核层和用户层之间的数据传输。具体来说:select函数在内核层会监视一组文件描述符的状态变化,并在有变化发生时通知用户层。为了是实现这个功能,内核会定期检测文件描述符的状态,并在发生变化时将相关信息传递给用户层。这个过程涉及到内核层和用户层之间的数据传输,即内核层需要将监视的文件描述符的状态信息传递给用户层。这个传输过程会涉及到系统资源的开销,因为需要进行数据拷贝操作,将内核中的数据拷贝到用户空间,这个数据拷贝的过程会消耗一定的系统资源。

            3. select必须轮询检测产生事件的文件描述符

            4. select只能工作在水平触发模式(低速模式),无法工作在边沿触发模式(高速模式)

                原因:

                    1. 在水平触发模式下,一旦文件描述符中的数据可读或可写,select就会通知用户程序,并且如果这些描述符在之后的select调用中仍然保持可读或可写状态,select会再次通知程序。换句话说,在水平触发模式下,只要描述符的状态处于可读或可写状态,select就会通知程序。

                    2. 在边缘触发模式下,只有当描述符的状态发生变化时才会通知程序,这意味着如果描述符中的数据量发生变化或者有新的数据到达,程序才会被通知,而如果描述符的状态保持不变,即使在之后的select调用中它任然处于可读或可写状态,程序也不会被通知。

            举例应用:

read.c

#include "head.h"int main(void)
{int fd = 0;int flags = 0;ssize_t nsize = 0;char *pret = NULL;fd_set rdfds;fd_set tmpfds;int ret = 0;char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}FD_ZERO(&rdfds);FD_SET(fd, &rdfds);FD_SET(0, &rdfds);while(1){tmpfds = rdfds;ret = select(fd+1, &tmpfds, NULL, NULL, NULL);if(ret == -1){perror("fail to select");return -1;}if(FD_ISSET(0, &tmpfds)){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}if(FD_ISSET(fd, &tmpfds)){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}close(fd);return 0;
}

        2. poll:

            1. poll有内核层向用户层数据空间拷贝的过程,占用系统资源开销

            2. poll必须轮询检测产生事件的文件描述符

            3. poll只能工作在水平触发模式(低速模式),无法工作在边沿触发模式(高速模式)

            举例应用:

read.c

#include "head.h"int main(void)
{int fd = 0;int ret = 0;int flags = 0;ssize_t nsize = 0;struct pollfd fds[2];char tmpbuff[1024] = {0};mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}fds[0].fd = 0;fds[0].events = POLLIN;fds[1].fd = fd;fds[1].events = POLLIN;while(1){ret = poll(fds, 2, -1);if(ret == -1){perror("fail to poll");return -1;}if(fds[0].revents & POLLIN){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}if(fds[1].revents & POLLIN){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}close(fd);return 0;
}

        3. epoll:

            举例应用:

read.c

#include "head.h"int main(void)
{int i = 0;int fd = 0;int epfd = 0;int nready = 0;ssize_t nsize = 0;char tmpbuff[1024] = {0};struct epoll_event env;struct epoll_event retenv[2];mkfifo("/tmp/myfifo", 0664);fd = open("/tmp/myfifo", O_RDONLY);if(fd == -1){perror("fail to open");return -1;}epfd = epoll_create(2);if(epfd == -1){perror("fail to epoll_create");return -1;}env.data.fd = 0;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &env);env.data.fd = fd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &env);while(1){nready = epoll_wait(epfd, retenv, 2, -1);if(nready == -1){perror("fail to epoll_wait");return -1;}for(i = 0; i < nready; i++){if(retenv[i].data.fd == 0){memset(tmpbuff, 0, sizeof(tmpbuff));gets(tmpbuff);printf("STDIN:%s\n", tmpbuff);}else if(retenv[i].data.fd == fd){memset(tmpbuff, 0, sizeof(tmpbuff));read(fd, tmpbuff, sizeof(tmpbuff));printf("FIFO:%s\n", tmpbuff);}}}close(fd);return 0;
}

3. 函数接口:

    1. select:

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

        功能:select监听文件描述符集合中是否有文件描述编程ready状态

        参数:

            nfds:最大文件描述符的值+1

            reafds:读文件描述符集合

            writefds:写文件描述符集合

            exceptfds:其余文件描述符集合

            timeout:等待的时长

                        NULL:一直等待

        返回值:

            成功返回文件描述符集合中的文件描述符个数
            失败返回-1

    void FD_CLR(int fd, fd_set *set);

                功能:判断文件描述符fd是否仍在集合中

    void FD_SET(int fd, fd_set *set);

                功能:将文件描述符fd加入到集合中

    int  FD_ISSET(int fd, fd_set *set);

                功能:判断文件描述符fd是否仍在集合中

    void FD_ZERO(fd_set *set);

                功能:将文件描述符集合清0

    2. poll:

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

        功能:监听文件描述符集合是否有事件发生

        参数:

            fds:监听文件描述符集合是否有时间发生

            nfds:监听文件描述符集合元素个数

            timeout:等待时间(-1一直等待)

struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */
};

                fd:监听的文件描述

                events:要监听的事件,POLLIN:是否可读,POLLOUT:是否可写

                revents:实际产生的事件

    3. epoll:

        1. epoll_create:
int epoll_create(int size);

            功能:创建一张内核事件表

            参数:

                size:事件的个数

            返回值:

                成功返回文件描述符
                失败返回-1

        2. epoll_ctl:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

            功能:维护epoll时间表

            参数:

                epfd:事件表的文件描述符

                op:

                    EPOLL_CTL_ADD     添加事件

                    EPOLL_CTL_MODE  修改事件

                    EPOLL_CTL_DEL      删除事件

                fd:操作的文件描述符

                events:事件对应的事件

typedef union epoll_data {void    *ptr;in    fd;uint32_t    u32;uint64_t    u64;
} epoll_data_t;struct epoll_event {uint32_t     events;      /* Epoll events */epoll_data_t data;        /* User data variable */
};

            返回值:

                成功返回0 
                失败返回-1 

        3. epoll_wait:
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

            功能:监听事件表中的事件

            参数:

                epfd:文件描述符

                events:存放实际产生事件的数组空间首地址

                maxevents:最多存放事件的个数

                timeout:设定监听的时间(超过该时间则不再监听)

                        -1:一直监听直到有事件发生

            返回值:

                成功返回产生事件的文件描述符个数
                失败返回-1 
                如果时间达到仍没有事件发生返回0

4. 练习作业:

        1. 编写TCP并发模型之select模型

client.c

#include "head.h"int CreateTcpClient(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in seraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){perror("fail to socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(pip);ret = connect(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (-1 == ret){perror("fail to connect");return -1;}return sockfd;
}int main(void)
{int sockfd = 0;char tmpbuff[4096] = {"hello world"};int cnt = 0;ssize_t nsize = 0;sockfd = CreateTcpClient("192.168.1.125", 50000);while (1){memset(tmpbuff, 0, sizeof(tmpbuff));sprintf(tmpbuff, "hello world --- %d", cnt);cnt++;nsize = send(sockfd, tmpbuff, strlen(tmpbuff), 0);if (-1 == nsize){perror("fail to send");return -1;}memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(sockfd, tmpbuff, sizeof(tmpbuff), 0);if (-1 == nsize){perror("fail to recv");return -1;}printf("RECV:%s\n", tmpbuff);}close(sockfd);return 0;
}

        后面的client.c都为上面所示

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int main(void)
{int i = 0;int ret = 0;int confd = 0;int sockfd = 0;fd_set rdfds;fd_set tmpfds;int maxfd = 0;sockfd = CreateListenSocket("192.168.1.125", 50000);FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = sockfd;while(1){tmpfds = rdfds;ret = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if(ret == -1){perror("fail to select");return -1;}if(FD_ISSET(sockfd, &tmpfds)){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");FD_CLR(sockfd, &rdfds);close(sockfd);continue;}FD_SET(confd, &rdfds);maxfd = maxfd > confd ? maxfd : confd;}for(i = sockfd+1; i <= maxfd; i++){if(FD_ISSET(i, &tmpfds)){ret = HandleTcpClient(i);if(ret == -1){fprintf(stderr, "handle client fialed!\n");FD_CLR(i, &rdfds);close(i);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");FD_CLR(i, &rdfds);close(i);continue;}}}}close(confd);close(sockfd);return 0;
}

        2. 编写TCP并发模型之poll模型

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int InitFds(struct pollfd *fds, int maxlen)
{int i = 0;for(i = 0; i < maxlen; i++){fds[i].fd = -1;}return 0;
}int AddFds(struct pollfd *fds, int maxlen, int fd, short env)
{int i = 0;for(i = 0; i < maxlen; i++){if(fds[i].fd == -1){fds[i].fd = fd;fds[i].events = env;break;}}if(i == maxlen){return -1;}return 0;
}int DeleteFds(struct pollfd *fds, int maxlen, int fd)
{int i = 0;for(i = 0; i < maxlen; i++){if(fds[i].fd == fd){fds[i].fd = -1;break;}}return 0;
}int main(void)
{int i = 0;int ret = 0;int nready = 0;int confd = 0;int sockfd = 0;struct pollfd fds[1024];sockfd = CreateListenSocket("192.168.1.125", 50000);InitFds(fds, 1024);AddFds(fds, 1024, sockfd, POLLIN);while(1){nready = poll(fds, 1024, -1);if(nready == -1){perror("fail to poll");return -1;}for(i = 0; i < 1024; i++){if(fds[i] == -1){continue;}if(fds[i].revents & POLLIN && fds[i].fd == sockfd){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");close(sockfd);DeleteFds(fds, 1024, sockfd);continue;}AddFds(fds, 1024, confd, POLLIN);}else if(fds[i].revents & POLLIN && fds[i].fd != sockfd){ret = HandleTcpClient(fds[i].fd);if(ret == -1){fprintf(stderr, "handle tcp client failed!\n");close(fds[i].fd);DeleteFds(fds, 1024, fds[i].fd);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");close(fds[i].fd);DeleteFds(fds, 1024, fds[i].fd);continue;}}}}close(confd);close(sockfd);return 0;
}

        3. 编写TCP并发模型之epoll模型

server.c

#include "head.h"int CreateListenSocket(char *pip, int port)
{int ret = 0;int sockfd = 0;struct sockaddr_in serveraddr;sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd == -1){perror("fail to socket");return -1;}serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(port);serveraddr.sin_addr.s_addr = inet_addr(pip);ret = bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));if(ret == -1){perror("fail to bind");return -1;}ret =listen(sockfd, 10);if(ret == -1){perror("fail to listen");return -1;}return sockfd;
}int HandleTcpClient(int confd)
{char tmpbuff[4096] = {0};ssize_t nsize = 0;memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recv(confd, tmpbuff, sizeof(tmpbuff), 0);if(nsize == -1){perror("fail to recv");return -1;}else if(nsize == 0){return 0;}sprintf(tmpbuff, "%s ------echo", tmpbuff);nsize = send(confd, tmpbuff, strlen(tmpbuff), 0);if(nsize == -1){perror("fail to send");return -1;}return nsize;}int main(void)
{int i = 0;int ret = 0;int nready = 0;int confd = 0;int sockfd = 0;struct epoll_event env;struct epoll_event retenv[1024];int epfd = 0;epfd = epoll_create(1024);if(epfd == -1){perror("fail to epoll_create");return -1;}sockfd = CreateListenSocket("192.168.1.125", 50000);env.data.fd = sockfd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &env);while(1){nready = epoll_wait(epfd, retenv, 1024, -1);if(nready == -1){perror("fail to epoll");return -1;}for(i = 0; i < nready; i++){if(retenv[i].data.fd == sockfd){confd = accept(sockfd, NULL, NULL);if(confd == -1){perror("fail to accept");close(sockfd);env.data.fd = sockfd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, &env);					continue;}env.data.fd = confd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_ADD, confd, &env);}else if(retenv[i].data.fd != sockfd){ret = HandleTcpClient(retenv[i].data.fd);if(ret == -1){fprintf(stderr, "handle tcp client failed!\n");close(retenv[i].data.fd);env.data.fd = retenv[i].data.fd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_DEL, retenv[i].data.fd, &env);continue;}else if(ret == 0){fprintf(stderr, "client disconnected!\n");close(retenv[i].data.fd);env.data.fd = retenv[i].data.fd;env.events = EPOLLIN;epoll_ctl(epfd, EPOLL_CTL_DEL, retenv[i].data.fd, &env);continue;}}}}close(confd);close(sockfd);return 0;
}

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

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

相关文章

案例分析篇01:软件架构设计考点架构风格及质量属性(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12601310.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

【SpringCloud微服务实战01】Eureka 注册中心

前言 在 Eureka 架构中,微服务角色有两类: EurekaServer :服务端,注册中心 记录服务信息 心跳监控 EurekaClient :客户端 Provider :服务提供者,例如案例中的 user-service 注册自己的信息到 EurekaS…

解决vue项目,运行npm install安装报缺少c++库问题

项目是前后端分离架构&#xff0c;前端使用的是vue框架&#xff0c;在部署前端项目时&#xff0c;需要下载安装一些基础的镜像配置&#xff0c;包括一些预处理&#xff0c;但是在使用npm install和yarn install命令时出现了如下错误&#xff0c;查阅资料总结如下&#xff1a; …

WPF(2)命令绑定

效果是&#xff1a;当TextBox控件的Text属性为空时show按钮不可用&#xff0c;有值时show按钮可用 项目结构 界面代码 <Window x:Class"WpfApp1.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://sc…

Flutter ios一键三连脚本

flutter运行ios时总得执行三个命令,中间还得等待&#xff0c;有没有脚本自动执行 ## ios 执行命令 - flutter clean - flutter pub get - cd ios - pod install有&#xff0c;项目根目录创建shell 文件夹&#xff0c;新建setup.sh setup.sh里面放如下代码 #!/bin/bash# ios …

ffmpeg解码和渲染理解

ffmpeg解码和渲染理解 ffmpeg视频解码步骤 FFmpeg 是一个功能强大的跨平台多媒体处理工具&#xff0c;包含了音视频编解码、封装/解封装、过滤器等功能。下面是一般情况下使用 FFmpeg 进行视频解码的步骤&#xff1a; 初始化 FFmpeg 库&#xff1a;首先需要初始化 FFmpeg 库&a…

【Sql】数据库的三范式?MySQL数据库引擎有?InnoDB与MyISAM的区别

目录 数据库的三范式&#xff1f; MySQL数据库引擎有&#xff1f; InnoDB与MyISAM的区别 数据库的三范式&#xff1f; 第一范式&#xff1a;是数据库最基本的要求&#xff0c;列不可再分 第二范式&#xff1a;行可以唯一区分&#xff0c;主键约束 第三范式&#xff1a;是在…

【深度学习笔记】7_4 动量法momentum

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 7.4 动量法 在7.2节&#xff08;梯度下降和随机梯度下降&#xff09;中我们提到&#xff0c;目标函数有关自变量的梯度代表了目标函数…

【ArcGIS】栅格数据进行标准化(归一化)处理

栅格数据进行标准化&#xff08;归一化&#xff09;处理 方法1&#xff1a;栅格计算器方法2&#xff1a;模糊分析参考 栅格数据进行标准化(归一化)处理 方法1&#xff1a;栅格计算器 栅格计算器&#xff08;Raster Calculator&#xff09; 方法2&#xff1a;模糊分析 空间…

Python实现图片(合并)转PDF

在日常的工作和学习过程当中,我相信很多人遇到过这样一个很普通的需求,就是将某一个图片转为PDF或者是将多个图片合并到一个PDF文件。但是,在苦苦搜寻一圈之后发现要么要下载软件,下载了还要注册,注册了还要VIP,甚至SVIP才能实现这样的需求! 今天,我带大家把这个功能打…

2024年华为HCIA-DATACOM新增题库(H12-811)

801、[单选题]178/832、在系统视图下键入什么命令可以切换到用户视图? A quit B souter C system-view D user-view 试题答案&#xff1a;A 试题解析&#xff1a;在系统视图下键入quit命令退出到用户视图。因此答案选A。 802、[单选题]“网络管理员在三层交换机上创建了V…

Kubernetes | 起源 | 组件详解

起源 起源&#xff1a; Kubernetes&#xff08;常简称为K8s&#xff09;起源于Google内部的Borg项目&#xff0c;是一个开源的容器编排引擎&#xff0c;于2014年首次对外发布。 Google Borg Google Borg 是 Google 内部开发和使用的大规模集群管理系统&#xff0c;用于管理和运…

Jmeter+Ant+Git/SVN+Jenkins实现持续集成接口测试,一文精通(二)

前言 上篇内容已经介绍接口测试流程以及了解如何用jmeter接口测试&#xff0c;本篇将介绍如何在实战中应用 一、Jmeter接口关联 1.使用正则表达式实现接口关联&#xff08;可以作用于任意值&#xff09; 如果说一个请求里面有多次请求服务器。 2.使用Jsonpath表达式实现接口关…

c++ primer plus笔记 第十八章 探讨c++新标准

复习前面的内容&#xff1a; 1.auto&#xff0c;可以自动识别auto本身在这种语境下是什么类型 2.decltype,让一个变量的类型和另外一个变量的类型相同 decltype(x) y;//让y的类型和x的类型相同 如何理解&#xff1f; decltype是一个关键词&#xff0c;其作用是检查括号内的…

Android studio虚拟调试出现“我的APP keeps stopping”问题

问题如图&#xff1a; 遇到这种情况&#xff0c;一看代码&#xff0c;也没有报错呀&#xff0c;怎么不能运行呢&#xff1f;不要慌&#xff01;我们一步一步来。 1、查看Logcat日志 在Android Studio中查看Logcat窗口&#xff0c;可以获取应用程序崩溃时的详细错误信息&…

【触想智能】工业触摸显示器在户外使用需要注意哪些问题?

工业显示器是智能制造领域应用比较广泛的电子产品&#xff0c;它广泛应用于工厂产线以及各种配套设备&#xff0c;在很大程度上提升了工厂的生产效率。 工业显示器按触摸方式分&#xff0c;可以分为工业触摸显示器和非触摸工业显示器两种;按使用环境分&#xff0c;又可以分为室…

几何变换 - 图像的缩放、翻转、仿射变换、透视等

1、前言 图像的几何变换是指改变图像的几何结构,大小、形状等等,让图像呈现出具备缩放、翻转、映射和透视的效果 图像的几何变换都比较复杂,计算也很复杂。 例如仿射变换,像素点的位置和灰度值都需要变换。 数字图像处理中利用后向传播的方法,将像素点变换后的位置通过…

腾讯云和阿里云4核8G云服务器多少钱一年和1个月费用对比

4核8G云服务器多少钱一年&#xff1f;阿里云ECS服务器u1价格955.58元一年&#xff0c;腾讯云轻量4核8G12M带宽价格是646元15个月&#xff0c;阿腾云atengyun.com整理4核8G云服务器价格表&#xff0c;包括一年费用和1个月收费明细&#xff1a; 云服务器4核8G配置收费价格 阿里…

案例分析篇08:Web架构设计相关20个考点(1~6)(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12601310.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

golang学习随便记16-反射

为什么需要反射 下面的例子中编写一个 Sprint 函数&#xff0c;只有1个参数&#xff08;类型不定&#xff09;&#xff0c;返回和 fmt.Fprintf 类似的格式化后的字符串。实现方法大致为&#xff1a;如果参数类型本身实现了 String() 方法&#xff0c;那调用 String() 方法即可…