libevent

libevent

库概念和特点

        开源。精简。跨平台(Windows、Linux、maxos、unix)。专注于网络通信(不一定非用在网络当中,比如下面的读写管道)。

        libevent特性:基于"事件",面向“文件描述符”的异步(回调)通信模型。

        异步:函数"注册"时间和函数真正被执行的时间不同,函数真正是被内核调用(等待某一条件满足)

事件库:就干一件事,监听文件描述符的库机制。

        先创建一个事件底座,然后创建你想监听的时间,插到底座上,libevent底座就会帮忙监听事件,当事件发生时,就会自动调用事件的回调函数。

libevent使用框架

常规事件

常规事件函数
//创建event_base(事件底座)
struct event_base* base = event_base_new();//创建事件event
常规事件event:event_new();
例如:
struct event* signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);buffer event:bufferevent_socket_new();//将事件添加到base上
int event_add(struct event* ev, const struct timeval* tv);//循环监听事件满足
int event_base_dispatch(struct event_base* base);
event_base_dispatch(base);					//调用//释放event_base
event_base_free(base);
其他函数

 

 libevent函数使用的一个简单的例子:
/*This example program provides a trivial server program that listens for TCPconnections on port 9995.  When they arrive, it writes a short message toeach client connection, and closes each connection once it is flushed.Where possible, it exits cleanly in response to a SIGINT (ctrl-c).
*/#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#ifndef _WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>static const char MESSAGE[] = "Hello, World!\n";static const int PORT = 9995;static void listener_cb(struct evconnlistener *, evutil_socket_t,struct sockaddr *, int socklen, void *);
static void conn_writecb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);//main函数中是使用框架,剩下外面的函数就是事件的回调
int main(int argc, char **argv)
{//创建事件底座指针struct event_base *base;struct evconnlistener *listener;
//创建事件指针struct event *signal_event;
//创建套接字的地址结构struct sockaddr_in sin;
#ifdef _WIN32WSADATA wsa_data;WSAStartup(0x0201, &wsa_data);
#endif
//真正创建事件底座base = event_base_new();if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;}memset(&sin, 0, sizeof(sin));
//初始化套接字的地址结构sin.sin_family = AF_INET;sin.sin_port = htons(PORT);
//一个函数干了套接字通信的 socket、listen、bind、accept几个函数的事情listener = evconnlistener_new_bind(base, listener_cb, (void *)base,LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,(struct sockaddr*)&sin,sizeof(sin));if (!listener) {fprintf(stderr, "Could not create a listener!\n");return 1;}
//注册一个信号事件signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);if (!signal_event || event_add(signal_event, NULL)<0) {fprintf(stderr, "Could not create/add a signal event!\n");return 1;}
//循环监听,相当于 while循环加里面的epoll_wait;下面的循环有很大概率没有机会调用event_base_dispatch(base);
//释放之前创建的事件evconnlistener_free(listener);event_free(signal_event);event_base_free(base);printf("done\n");return 0;
}//下面是千篇一律,定义了三个回调,分别独立对应三个事件。看一个就行
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *sa, int socklen, void *user_data)
{struct event_base *base = user_data;struct bufferevent *bev;bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);if (!bev) {fprintf(stderr, "Error constructing bufferevent!");event_base_loopbreak(base);return;}bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);bufferevent_enable(bev, EV_WRITE);bufferevent_disable(bev, EV_READ);bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}static void conn_writecb(struct bufferevent *bev, void *user_data)
{struct evbuffer *output = bufferevent_get_output(bev);if (evbuffer_get_length(output) == 0) {printf("flushed answer\n");bufferevent_free(bev);}
}static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{if (events & BEV_EVENT_EOF) {printf("Connection closed.\n");} else if (events & BEV_EVENT_ERROR) {printf("Got an error on the connection: %s\n",strerror(errno));/*XXX win32*/}/* None of the other events can happen here, since we haven't enabled* timeouts */bufferevent_free(bev);
}static void signal_cb(evutil_socket_t sig, short events, void *user_data)
{struct event_base *base = user_data;struct timeval delay = { 2, 0 };printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");event_base_loopexit(base, &delay);
}
常规事件函数使用详解
*事件创建 event_new:
struct event* event_new(struct event_base* base,evutil_socket_t fd,short what,event_callback_fd cb,void* arg);
//
参数:
base:基事件, 也就是event_base_new()的返回值
fd:绑定到event上的文件描述符,监听的对象
what:文件描述符对应的事件(r/w/e),监听类型是什么what的取值:EV_READ:读一次后,退出循环EV_WRITE:写一次,退出循环EV_PERSIST:持续触发,可以理解为while(read())或while(write())
cb:一旦满足监听条件,回调的函数
arg:回调函数的参数//返回值:成功返回创建的事件对象event
事件回调函数:

参数跟上面一致(实际用时候不用传参)

typedef void (*event_callback_fn)(evutil_socket_t fd,short what,void* arg);
f
事件添加(到event_base上)
int event_add(struct event* ev,const strcut timeval* tv);
//参数:
ev是要添加的事件对象,就是event_new的返回值
tv一般传NULL,表示一直等到事件被触发,回调函数才会被调用。如果传非0,会等待事件被触发,如果事件一直不触发,时间到,回调函数依然会被调用//返回值:成功返回0;失败返回-1
事件删除(对应add,从event_base上摘下事件(不常用)):
int event_del(struct event* ev);
//ev是要摘下的事件对象,就是event_new的返回值
事件销毁:
int event_free(strcut event* ev);
//ev是要销毁的事件对象,就是event_new的返回值
基于libevent实现的FIFO的读写
读FIFO进程:
void perr_exit(const char* str) {perror(str);exit(1);
}
//读回调
void read_cb(evutil_socket_t fd, short what, void* arg) {char buf[BUFSIZ] = {0};read(fd, buf, sizeof(buf));printf("Read from writer:%s\n", buf);printf("what=%s\n", what & EV_READ ? "Yes" : "No");sleep(1);return;
}int main(int argc, char* argv[]) {int ret = 0;int fd = 0;unlink("myfifo");mkfifo("myfifo", 0644);fd = open("myfifo", O_RDONLY | O_NONBLOCK);//借助epoll反应堆,默认都是非阻塞if (fd == -1)perr_exit("open error");
//读管道时候,管道中不一定有数据,此时就需要有事件概念介入了
//创建事件基座struct event_base* base = event_base_new();struct event* ev = NULL;
//创建事件ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);
//添加到事件基座event_add(ev, NULL);
//开启事件监听event_base_dispatch(base);
//释放事件event_base_free(base);close(fd);return 0;
}
写FIFO进程:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>// 对操作处理函数
void write_cb(evutil_socket_t fd, short what, void *arg)
{// write管道char buf[1024] = {0};static int num = 0;sprintf(buf, "hello,world-%d\n", num++);write(fd, buf, strlen(buf)+1);sleep(1);
}// 写管道
int main(int argc, const char* argv[])
{// open file//int fd = open("myfifo", O_WRONLY | O_NONBLOCK);int fd = open("myfifo", O_WRONLY);if(fd == -1){perror("open error");exit(1);}// 写管道struct event_base* base = NULL;base = event_base_new();// 创建事件struct event* ev = NULL;// 检测的写缓冲区是否有空间写//ev = event_new(base, fd, EV_WRITE , write_cb, NULL);ev = event_new(base, fd, EV_WRITE | EV_PERSIST, write_cb, NULL);// 添加事件event_add(ev, NULL);// 事件循环event_base_dispatch(base);// 释放资源event_free(ev);event_base_free(base);close(fd);return 0;
}
 重点关注对写事件event_new函数入参,写监听时长的定义,写一次退出循环和一直触发的区别:

libevent模型,事件的运行状态:未决和非未决

未决:有资格被处理,但还没有被处理 (只剩数据没到达了)

非未决:没有资格被处理 (除了数据没到达,还有其他监听条件没满足,比如事件没add)

小注意:事件被处理完,如果设置了persist,add会被再调用一次
在这里插入图片描述

bufferevent

bufferevent概念

bufferevent的事件对象fd有两个缓冲区。

读:读缓冲区有数据,读回调函数被调用,使用bufferevent_read()读数据

写:使用bufferevent_write,向写缓冲中写数据,该缓冲区中有数据自动写出,写完后,回调函数被调用(鸡肋)

在这里插入图片描述

原理:bufferent利用队列实现两个缓冲区(数据只能读一次,读走就没, FIFO)

bufferevent事件对象创建和销毁
创建socket事件对象 bufferevent_socket_new:
struct bufferevent* bufferevent_socket_new(struct event_base* base,evutil_socket_t fd,enum bfferevent_options options)
//入参
base:基事件,event_base_new函数的返回值
fd:封装到bufferevent内的fd(绑定在一起),即lfd
enum表示枚举类型,一般取BEV_OPT_CLOSE_ON_FREE(关闭时释放底层套接字)//返回
成功返回bufferevent事件对象

对比event,有区别。这个不是在 new的时候设置的回调,而是借助后面的 bufferevent_setcb函数专门设置回调。

销毁事件对象 bufferevent_socket_free:
void bufferevent_socket_free(struct bufferevent* ev)
//入参
bufev:bufferevent_socket_new()函数的返回值readcb:读缓冲对应的回调,自己封装,在其内部读数据(注意是用bufferevent_read()读,而不是read())writecb:鸡肋,传NULL即可eventcb:可传NULLcbarg:回调函数的参数
给bufferevent事件设置回调 bufferevent_setcb
void bufferevent_setcb(struct bufferevent* bufev,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void* cbarg);
//入参:
bufev:bufferevent_socket_new()函数的返回值readcb:读缓冲对应的回调,自己封装,在其内部读数据(注意是用bufferevent_read()读,而不是read())writecb:鸡肋,传NULL即可eventcb:备用回调,比如异常回调,也可传NULLcbarg:三个回调函数的(相同)参数
 readcb对应的回调函数:

void read_cb(struct bufferevent* bev,void* arg){...bufferevent_read();
}

为什么 read_cb里面不封装read,因为没有fd给read传。fd通过new函数封装好的bufferevent传。

size_t bufferevent_read(struct bufferevent* bufev,void* data,size_t size);
writecb对应的回调函数:

int bufferevent_write(struct bufferevent* bufev,const void* data,size_t size)
eventcb对应的回调函数:
typedef void (*bufferevent_event_cb)(struct bufferevent* bev,short events,void* ctx)

buffer缓冲区开启和关闭

默认新建的bufferevent写缓冲是enable的,而读缓冲是disable的

通过下面函数操作缓冲区读写使能:

 

void bufferevent_enable(struct bufferevent* bufev,short events);		//启用缓冲区
void bufferevnet_disable(struct bufferevent* bufev,short events);		//禁用/*例如:开启读缓冲*/
void bufferevent_enable(bufev,EV_READ);//events的值可传入三个宏:
EV_READ
EV_WRITE
EV_READ|EV_WRITE

也可获取缓冲区的禁用状态:

short bufferevent_get_enable(struct bufferevent* bufev)
客户端和服务器连接和监听函数详解
客户端建立连接 bufferevent_socket_connect:
int bufferevent_socket_connect(struct bufferevent* bev,struct sockaddr* address,int addrlen);//入参
bev:bufferevent事件对象(封装了fd)
address,len:等同于connect()的参2和参3
服务器创建监听器对象 evconnlistener_new_bind:

这一个函数可以完成socket(),bind(),listen(),accept()四个函数的作用

struct evconnlistener* evconnlistener_new_bind(struct event_base* base,evconnlistener_cb cb,void* ptr,unsigned flags,int backlog,const struct sockaddr* sa,int socklen);
//入参
cb:监听回调函数(建立连接后用户要做的操作)
ptr:回调函数的参数
flags:可识别的标志,通常传:
​ LEV_OPT_CLOSE_ON_FREE(释放bufferevent时关闭底层传输端口, 这将关闭底层套接字, 释放底层bufferevent等)
​ LEV_OPT_REUSEABLE(可以设置端口复用)
backlog:相当于listen的参2,最大连接数, 传-1表示使用默认的最大值
sa:服务器自己的地址结构
socklen:sa的大小

回调函数 evconnlistener_cb cb:

监听成功后,说明客户端链接成功,原来的accept传出的客户端地址结构,现在在这里传出。

typedef void (*evconnlistener_cb)(struct evconnlistener* listener,evutil_socker_t sock,struct sockaddr* addr,int len,void* ptr);
//入参:
listener:evconnlistener_new_bind 的返回值
sock:用于通信的文件描述符,即cfd
addr:传出,客户端的地址结构
len:客户端地址结构的长度
ptr:外部ptr传进来的值
libevent实现TCP服务器流程

感觉这个思路和epoll反应堆还有些距离??? 

  • 创建基事件event_base
  • 使用evconlistener_new_bind()创建监听服务器,用来专门监听客户端链接事件,有新链接上来,就调用其回调函数(完成socket(),bind(),listen(),accept()四个函数的作用
  • 设置evconlistener_new_bind()回调函数listner_cb(),该回调函数被调用,说明有一个新的客户端连接上来,会得到一个新的fd,用于跟客户端通信。
  • 创建bufferevent事件对象:bufferevent_socket_new(),将fd封装到这个事件对象中
  • 使用bufferevent_setcb()函数给bufferevent的read,write,event设置回调函数
  • 设置读写缓冲enable
  • 启动循环event_base_dispath(),监听通信事件()
  • 当监听的事件满足时,read_cb会被调用,在其内部bufferevent_read(),读
  • 释放连接
libevent实现TCP服务器源码分析
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>// 读缓冲区回调
void read_cb(struct bufferevent *bev, void *arg)
{char buf[1024] = {0};   bufferevent_read(bev, buf, sizeof(buf));printf("client say: %s\n", buf);char *p = "我是服务器, 已经成功收到你发送的数据!";// 发数据给客户端bufferevent_write(bev, p, strlen(p)+1);//执行完后回调write_cbsleep(1);
}// 写缓冲区回调
void write_cb(struct bufferevent *bev, void *arg)
{printf("I'm服务器, 成功写数据给客户端,写缓冲区回调函数被回调...\n"); 
}// 事件
void event_cb(struct bufferevent *bev, short events, void *arg)
{if (events & BEV_EVENT_EOF){printf("connection closed\n");  }else if(events & BEV_EVENT_ERROR)   {printf("some other error\n");}bufferevent_free(bev);    printf("buffevent 资源已经被释放...\n"); 
}void cb_listener(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr)
{printf("connect new client\n");struct event_base* base = (struct event_base*)ptr;//创建出用于通信的socket事件对象bufferevent,并给bufferevent缓冲区设置回调和读使能struct bufferevent *bev;//2参fd被封装在新的事件对象 bufferevent中bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);bufferevent_enable(bev, EV_READ);
}int main(int argc, const char* argv[])
{// init server struct sockaddr_in serv;memset(&serv, 0, sizeof(serv));serv.sin_family = AF_INET;serv.sin_port = htons(9876);serv.sin_addr.s_addr = htonl(INADDR_ANY);struct event_base* base;base = event_base_new();// 创建套接字// 绑定// 接收连接请求struct evconnlistener* listener;listener = evconnlistener_new_bind(base, cb_listener, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36, (struct sockaddr*)&serv, sizeof(serv));event_base_dispatch(base);evconnlistener_free(listener);event_base_free(base);return 0;
}
客户端流程简析和回顾
  1. 创建event_base
  2. 使用bufferevent_socket_new()创建一个用跟服务器通信的bufferevent事件对象
  3. 使用bufferevent_socket_connect连接服务器
  4. 使用bufferevent_setcb()给bufferevent对象的read,write,event设置回调
  5. 设置bufferevent对象的读写缓冲区使能 (4、5放connect前应该也没问题)
  6. 接受,发送数据bufferevent_read()/bufferevent_write()
  7. 启动循环监听event_base_dispath()
  8. 释放资源
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/bufferevent.h>
#include <event2/event.h>
#include <arpa/inet.h>void read_cb(struct bufferevent *bev, void *arg)
{char buf[1024] = {0}; bufferevent_read(bev, buf, sizeof(buf));printf("fwq say:%s\n", buf);bufferevent_write(bev, buf, strlen(buf)+1);sleep(1);
}void write_cb(struct bufferevent *bev, void *arg)
{printf("----------我是客户端的写回调函数,没卵用\n"); 
}void event_cb(struct bufferevent *bev, short events, void *arg)
{if (events & BEV_EVENT_EOF){printf("connection closed\n");  }else if(events & BEV_EVENT_ERROR)   {printf("some other error\n");}else if(events & BEV_EVENT_CONNECTED){printf("已经连接服务器...\\(^o^)/...\n");return;}// 释放资源bufferevent_free(bev);
}// 客户端与用户交互,从终端读取数据写给服务器
void read_terminal(evutil_socket_t fd, short what, void *arg)
{// 读数据char buf[1024] = {0};int len = read(fd, buf, sizeof(buf));struct bufferevent* bev = (struct bufferevent*)arg;// 发送数据bufferevent_write(bev, buf, len+1);
}int main(int argc, const char* argv[])
{struct event_base* base = NULL;base = event_base_new();int fd = socket(AF_INET, SOCK_STREAM, 0);// 通信的fd放到bufferevent中struct bufferevent* bev = NULL;bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);// init server infostruct sockaddr_in serv;memset(&serv, 0, sizeof(serv));serv.sin_family = AF_INET;serv.sin_port = htons(9876);inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);// 连接服务器bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));// 设置回调bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);// 设置读回调生效// bufferevent_enable(bev, EV_READ);// 创建事件struct event* ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST,read_terminal, bev);// 添加事件                     event_add(ev, NULL);event_base_dispatch(base);event_free(ev);event_base_free(base);return 0;
}

 

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

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

相关文章

软件开发项目文档系列之十如何撰写测试用例

目录 1 概述1.1 编写目的1.2 定义1.3 使用范围1.4 参考资料1.5 术语定义 2 测试用例2.1 功能测试2.1.1 用户登录功能2.1.2 商品搜索功能 2.2 性能测试2.2.1 网站响应时间2.2.2 并发用户测试 附件&#xff1a; 测试用例撰写的要素和注意事项附件1 测试用例要素附件2 测试用例的注…

【鸿蒙软件开发】ArkUI容器组件之Grid(网格布局)

文章目录 前言一、Grid1.1 子组件GridItem是什么子组件接口属性事件示例代码 1.2 接口参数 1.3 属性1.4 Grid的几种布局模式1.5 GridDirection枚举说明1.6事件ItemDragInfo对象说明 1.7 示例代码 总结 前言 Grid容器组件&#xff1a;网格容器&#xff0c;由“行”和“列”分割…

【数据结构初级(2)】单链表的基本操作和实现

文章目录 Ⅰ 概念及结构1. 单链表的概念2. 单链表的结构 Ⅱ 基本操作实现1. 定义单链表结点2. 创建新结点3. 单链表打印4. 单链表尾插5. 单链表头插6. 单链表尾删7. 单链表头删8. 单链表查找9. 在指定 pos 位置前插入结点10. 删除指定 pos 位置的结点11. 单链表销毁 本章实现的…

P02项目(学习)

★ P02项目 项目描述&#xff1a;安全操作项目旨在提高医疗设备的安全性&#xff0c;特别是在医生离开操作屏幕时&#xff0c;以减少非授权人员的误操作风险。为实现这一目标&#xff0c;我们采用多层次的保护措施&#xff0c;包括人脸识别、姿势检测以及二维码识别等技术。这些…

数据结构-邻接表广度优先搜索(C语言版)

对于一个有向图无向图&#xff0c;我们下面介绍第二种遍历方式。 广度优先搜索&#xff0c;即优先对同一层的顶点进行遍历。 如下图所示&#xff1a; 该例子&#xff0c;我们有六个顶点&#xff0c; 十条边。 对于广度优先搜索&#xff0c;我们先搜索a&#xff0c;再搜索abc…

5、Python中的变量和表达式:变量的定义、赋值和数据类型转换

文章目录 Python中的变量和表达式:变量的定义、赋值和数据类型转换变量的定义变量的赋值数据类型转换注意事项表达式总结Python中的变量和表达式:变量的定义、赋值和数据类型转换 Python是一种高级编程语言,以其简洁明了的语法和强大的功能而闻名。在Python编程中,变量和表…

力扣第121题 买卖股票的最佳时机 c++ 动态规划解法 熟练dp思维 之简单题 附Java代码

题目 &#xff08;在我以前有贪心解法&#xff0c;也可以去参考参考&#xff09; 贪心解法 股票问题https://blog.csdn.net/jgk666666/article/details/133978629 121. 买卖股票的最佳时机 简单 相关标签 数组 动态规划 给定一个数组 prices &#xff0c;它的第 i 个元…

NVMe FDP会被广泛使用吗?

文章开头&#xff0c;我们需要先了解固态硬盘的读写机制。我们知道&#xff0c;固态硬盘的存储单元是由闪存颗粒组成的&#xff0c;无法实现物理性的数据覆盖&#xff0c;只能擦除然后写入&#xff0c;重复这一过程。因而&#xff0c;我们可以想象得到&#xff0c;在实际读写过…

Mac VsCode g++编译报错:不支持C++11语法解决

编译运行时报错&#xff1a; [Running] cd “/Users/yiran/Documents/vs_projects/c/” && g 1116.cpp -o 1116 && "/Users/yiran/Documents/vs_projects/c/"1116 1116.cpp:28:22: warning: range-based for loop is a C11 extension [-Wc11-extensi…

Maven3.9.1安装及环境变量配置

一、Maven的下载与安装 maven各版本下载地址 打开链接后自行选择对应版本 下载完成后解压安装,最好别选择c盘,安装目录路径等使用英文,避免产生其他问题 我这里选择的是D盘 二、Maven的环境变量配置 2.1、右键点击此电脑选择属性&#xff0c;点击高级系统设置&#xff0c;点…

jenkins结合k8s部署动态slave

1、完成k8s连接 在完成jenkins的部署后现安装kubernets的插件 如果jenkins 是部署在k8s集群中只需要填写一下 如果是非本集群的部署则需要填写证书等 cat ./config echo ‘certificate-authority-data-value’ | base64 -d > ./ca.crt echo ‘client-certificate-data’ |…

结合组件库实现table组件树状数据的增删改

如图所示&#xff0c;可以实现树状数据的新增子项&#xff0c;新增平级&#xff0c;删除。主要用到了递归 代码&#xff1a; <template><el-table :data"tableData" style"width: 100%; margin-bottom: 20px" row-key"id" border def…

uniapp使用技巧及例子

前言 uniapp&#xff08;Universal Application&#xff09;是一种基于Vue.js的全端解决方案&#xff0c;允许开发者使用一套代码构建多个平台的应用程序。这些平台包括iOS、Android、H5、微信小程序、支付宝小程序等。uniapp的出现解决了跨平台开发的痛点&#xff0c;大大减少…

ce从初阶到大牛--动态网络部署

1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! systemctl stop firewalld setenforce 0 cd /etc/httpd/conf.d/ vim openlab.conf ** <VirtualHost 192.168.170.100:80>DocumentRoot /www/openlabServerName 192.168.170.100 </VirtualHost>…

排序算法之-选择

算法原理 在未排序的数列中找出最大&#xff08;或最小&#xff09;的元素&#xff0c;然后将其存入到已排序的数列起始位置&#xff0c;紧接着在剩余的未排序数列中继续查找最大&#xff08;或最小&#xff09;的元素&#xff0c;并将其放入到已排序的数列末尾&#xff0c;依…

行情分析——加密货币市场大盘走势(11.6)

大饼昨日下跌过后开始有回调的迹象&#xff0c;现在还是在做指标修复&#xff0c;大饼的策略保持逢低做多。稳健的依然是不碰&#xff0c;目前涨不上去&#xff0c;跌不下来。 以太周五给的策略&#xff0c;入场的已经止盈了&#xff0c;现在已经达到1884&#xff0c;已经全部吃…

Java —— 类和对象(一)

目录 1. 面向对象的初步认知 1.1 什么是面向对象 1.2 面向对象与面向过程 2. 类定义和使用 2.1 认识类 2.2 类的定义格式 3. 类的实例化(如何产生对象) 3.1 什么是实例化 3.2 访问对象的成员 3.3 类和对象的说明 4. this引用 4.1 为什么要有this引用 4.2 什么是this引用 4.3 th…

十一、K8S之持久化存储

持久化存储 一、概念 在K8S中&#xff0c;数据持久化可以让容器在重新调度、重启或者迁移时保留其数据&#xff0c;并且确保数据的可靠性和持久性。 持久化存储通常用于程序的状态数据、数据库文件、日志文件等需要在容器生命周期之外的数据&#xff0c;它可以通过各种存储解…

3.27每日一题(常系数线性非齐次方程的特解)

常系数非齐次线性方程的特解如何假设&#xff08;两种&#xff09;形式&#xff1a; 1、题目中 e 的 x 次幂以及 1&#xff0c;都是第一种&#xff1a;1可以看成为e的0次幂 注&#xff1a;题目给的多项式是特殊的形式&#xff0c;我们要设为一般的形式的多项式 2、题目中sin…

css基础之实现轮播图

原理介绍 图片轮播的原理是通过控制显示和隐藏不同的图片来实现图像的切换&#xff0c;从而创建连续播放的效果。用到的知识点有定位和定时器。 实现步骤&#xff1a; HTML 结构&#xff1a; 首先&#xff0c;需要在HTML中创建一个包含轮播图片的容器&#xff0c;通常使用 &l…