当前位置: 首页 > news >正文

Linux网络编程Socket通信6-Libevent移植与使用

目录

  • libevent
    • libevent交叉编译并移植
    • libevent安装
      • 安装步骤
      • 测试代码
      • libevent执行报错解决
    • libevent_base根节点
      • event_base_new
      • event_base_free
      • event_reinit
    • event_loop循环等待事件
      • event_base_loop
      • event_base_dispatch
      • event_base_loopexit
      • event_base_loopbreak
    • event事件
      • event_new
      • event_add
      • event_del
      • event_free
      • levent事件监听流程
      • event事件实现TCP代码
    • bufferevent事件
      • bufferevent_socket_new
      • bufferevent_setcb
      • bufferevent_enable、bufferevent_disable
      • bufferevent_write
      • bufferevent_read
      • evconnlistener_new_bind
      • bufferevent_socket_connect
      • evconnlistener_free
      • bufferevent事件监听流程
    • bufferevent实现TCP服务器
    • bufferevent实现TCP客户端

libevent

libevent是一个事件通知库;封装了reactor。Libevent支持Linux、Unix和Windows。对I/O事件、信号和定时事件提供统一的处理。使用libevent_pthread库来提供线程安全支持。基于Reactor模式实现。事件驱动、高性能、轻量级、专注于网络、跨平台、支持多种I/O多路复用技术、支持I/O,定时器和信号事件、注册事件优先级。

libevent交叉编译并移植

tar zxvf libevent-2.1.8-stable.tar.gz # 解压
cd libevent-2.1.8-stable
./configure --prefix=/xxx/install --host=arm-linux-gnueabihf
make
make install
cd /xxx/install
tar -zcvf libevent-2.1.12-install.tar.gz lib/*.so*# 将 libevent-2.1.12-install.tar.gz 复制到开发板上
# 新建文件夹:/usr/local/lib/libevent , 然后解压到该文件夹中
sudo mkdir /usr/local/lib/libevent
sudo tar -zxf ./libevent-2.1.12-install.tar.gz --strip-components 1 -C /usr/local/lib/libevent
# 开发板上添加库文件搜索路径
sudo vi /etc/ld.so.conf.d/libc.conf
# 在 /etc/ld.so.conf 文件中添加库的搜索路径
/usr/local/lib/libevent //根据自己的库路径添加
# 然后 ldconfig 生成/etc/ld.so.cache,可用ldconfig -v 查看
ldconfig

libevent安装

安装步骤

  • tar zvxf libevent-2.1.8-stable.tar.gz -C ./
  • cd libevent-2.1.8-stable
  • sudo ./configure
  • sudo make
  • sudo make install
  • ls -al /usr/local/lib | grep libevent
  • 默认如此安装的库路径:/usr/local/lib 头文件目录:/usr/lcoal/include
  • 编译的时候需要指定库名: -levent

测试代码

#include <event.h>
#include <stdio.h>int main()
{char ** methods = event_get_supported_methods();//获取libevent后端支持的方法int i =0;for(i = 0; methods[i] != NULL; i++){printf("%s\n",methods[i]);}struct event_base *base = event_base_new();printf("----%s\n",event_base_get_methods(base));return 0;
}/**
dongfang@dongfang-virtual-machine:~/NetWorkProgramming$ ./getmethods     
epoll
poll
select
----epoll
*/

编译:gcc getmethods.c -o getmethods -levent

libevent执行报错解决

解决报错:error while loading shared libraries: libevent-2.1.so.6: cannot open shared object file: No such file or directory

ldd getmethods 
linux-vdso.so.1 (0x00007ffdcc7dd000)
libevent-2.1.so.6 => not find
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1f4e200000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1f4e4ea000)find / -name libevent-2.1.so.6 --> 找到该文件在 /usr/local/lib下面LD_DEBUG=libs ./getmethods -v # 查看程序搜索库时的路径可发现他寻找的地址为 /usr/lib/libevent-2.1.so.6 , 所以我们需要添加软链接过去
sudo ln -s /usr/local/lib/libevent-2.1.so.6 /usr/lib/libevent-2.1.so.6

在 .libs 隐藏文件中包含全部libevent已经编译好的so文件。其中core为libevent的核心文件,libevent.so为主链接文件,会关联到其他全部so文件。在sample目录下会有已经编译好的服务器应用程序。在libevent的源码中的sample目录下面提供了很多例子。

libevent_base根节点

event_base_new

使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个event_base 结构体持有一个事件集合**,**可以检测以确定哪个事件是激活的。**event_base_new()**函数分配并且返回一个新的具有默认设置的 event_base。函数会检测环境变量,返回一个到 event_base 的指针。如果发生错误,则返回 NULL。选择各种方法时,函数会选择 OS 支持的最快方法。

struct event_base *event_base_new(void);

event_base_free

申请到的 event_base 指针通过 event_base_free 函数进行释放。

void event_base_free(struct event_base *base)

event_reinit

如果fork出子进程,想在子进程继续使用event_base,那么子进程需要对event_base重新初始化,函数如下:

int event_reinit(struct event_base *base)

event_loop循环等待事件

event_base_loop

创建好libevent_base根节点后,需要等待事件的产生,也就是等待想要等待的事件的激活,在libevent中提供了对应的接口,类似 while(1){ epoll_wait() } 的功能函数。

int event_base_loop(struct event_base* base, int flags);
flags的取值:#define EVLOOP_ONCE	0x01 只触发一次,如果事件没有被触发,那么就阻塞等待#define EVLOOP_NONBLOCK	0x02 非阻塞方式检测事件是否触发

event_base_dispatch

大多时候我们会调用另一个api,它相当于flags=0时候的event_base_loop函数

int event_base_dispatch(struct event_base *base);
该函数相当于没有设置标志位的event_base_loop。程序会一直运行下去,直到没有需要检测的事件了,或者被结束循环的api终止。

event_base_loopexit

等待一定时间后退出循环

int event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
struct timeval{long tv_sec;long tv_usec;
};

event_base_loopbreak

直接退出循环

int event_base_loopbreak(struct event_base *event_base)

event事件

event_new

生成新事件,使用 event_new()接口创建事件。

struct event *event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn cb, void *arg);
base: event_base根节点
fd: 上树的文件描述符
events: 监听的事件#define EV_TIMEOUT 0x01 // 超时事件#define EV_READ 0x02 // 读事件#define EV_WRITE 0x04 // 写事件#define EV_SIGNAL 0x08 // 信号事件#define EV_PERSIST 0x10 // 周期性触发#define EV_ET 0x20 // 设置边沿触发
cb: void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg);回调函数
arg: 传入回调函数的参数

event_add

构造事件之后,在将其添加到 event_base 之前实际上是不能对其做任何操作的。使用event_add()将事件添加到 event_base。

int event_add(struct event *ev, const struct timeval *tv);
ev:上树节点的地址
tv: NULL 永久监听,固定时间 限时等待

event_del

int event_del(struct event *ev);

event_free

void event_free(struct event *ev);

levent事件监听流程

  • 创建套接字 socket -> 绑定 bind -> 监听 listen
  • 创建 event_base(event_base_new) -> 初始化上树节点 event_new
  • 上树 event_add -> 循环监听 event_base_dispatch
  • 其他收尾等 event_base_free、close。

event事件实现TCP代码

#include <stdio.h>
#include <event.h>
#include "wrap.h"#define MAX 1000
// 用于保存accept到的各个客户端的cfd以及上树节点
struct eventfd {evutil_socket_t fd;struct event *ev;
}event_fd[MAX];void init_event_fd(void)
{int i = 0;for(i = 0;i < MAX; i++){event_fd[i].fd = -1;event_fd[i].ev = NULL;}
}void set_event_fd(evutil_socket_t fd, struct event* ev)
{int i = 0;for(i = 0; i < MAX; i++){if(event_fd[i].fd == -1)break;}if(i == MAX)exit(1);event_fd[i].fd = fd;event_fd[i].ev = ev;
}int find_event_fd(int fd)
{int i = 0;for(i = 0; i < MAX; i++){if(event_fd[i].fd == fd)break;}if(i == MAX){printf("not find fd = %d\n",fd);exit(1);}return i;
}void cfd_cb(evutil_socket_t cfd, short events, void* arg)
{char buf[1500] = "";memset(buf, 0, 1500);int n = Read(cfd, buf, sizeof(buf));if(n <= 0){perror("err or close!\n");int i = find_event_fd(cfd);event_del(event_fd[i].ev);event_free(event_fd[i].ev);Close(cfd);event_fd[i].fd = -1;event_fd[i].ev = NULL;}else{printf("%s\n",buf);Write(cfd, buf, n);}}void lfd_cb(evutil_socket_t lfd, short events, void* arg)
{struct event_base *base = (struct event_base*)arg;int cfd = Accept(lfd, NULL, NULL);if(cfd < 0){perror("Accept error");return;}struct event *ev = event_new(base, cfd, EV_READ | EV_PERSIST, cfd_cb, NULL);event_add(ev, NULL);set_event_fd(cfd, ev);
}int main(int argc, char* argv[])
{init_event_fd();// 创建套接字并绑定,返回服务器套接字int lfd = tcp4bind(8000, NULL);// 监听Listen(lfd, 128);// 创建event_basestruct event_base* base = event_base_new();// 初始化lfd上树节点struct event* ev = event_new(base, lfd, EV_READ | EV_PERSIST, lfd_cb, base);// 上树event_add(ev, NULL);// 循环监听event_base_dispatch(base);Close(lfd);event_base_free(base);return 0;
}

bufferevent事件

bufferevent 是 libevent 中的一个事件缓冲 IO,内部实现了基本 socket recv/send 操作 ,用户只需要调用 bufferevent 的 API 即可实现数据的读写。libevent的bufferevent事件对应一个文件描述符、两个缓冲区、三个回调函数。在libevent的应用层有读写缓冲区,对应底层的读写缓冲区。底层的读缓冲区数据拷贝到应用层缓冲区会触发读回调,从应用层缓冲区将数据写入底层缓冲区会触发写回调。还有一个事件回调,用于出错、断开连接等触发的事件回调。

bufferevent_socket_new

创建新的节点

struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
base : 根节点
fd : 文件描述符
options : enum bufferevent_options {// 释放bufferevent自动关闭底层接口fdBEV_OPT_CLOSE_ON_FREE = (1<<0),//使bufferevent能够在多线程下是安全的BEV_OPT_THREADSAFE = (1<<1),// 使事件循环中延迟运行回调BEV_OPT_DEFER_CALLBACKS = (1<<2),// 执行回调时不会在缓冲区事件上保留锁, 要求BEV_OPT_DEFER_CALLBACKS同时也被设置// 将来BEV_OPT_UNLOCK_CALLBACKS可能会被libevent作者考虑删除BEV_OPT_UNLOCK_CALLBACKS = (1<<3)
};
返回值:初始化新建节点的地址

bufferevent_setcb

设置节点回调

void bufferevent_setcb(struct bufferevent *bufev,bufferevent_data_cb readcb, bufferevent_data_cb writecb,bufferevent_event_cb eventcb, void *cbarg);
bufev: 新建节点的地址
readcb: 读回调
writecb:写回调
eventcb:事件异常回调
cbarg: 传给回调函数的参数
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
what: 
#define BEV_EVENT_READING	0x01	/**< error encountered while reading */
#define BEV_EVENT_WRITING	0x02	/**< error encountered while writing */
#define BEV_EVENT_EOF		0x10	/**< eof file reached /对方关闭连接 */
#define BEV_EVENT_ERROR		0x20	/**< unrecoverable error encountered */
#define BEV_EVENT_TIMEOUT	0x40	/**< user-specified timeout reached */
#define BEV_EVENT_CONNECTED	0x80	/**< connect operation finished. */

bufferevent_enable、bufferevent_disable

事件回调的使能和不使能函数

int bufferevent_enable(struct bufferevent *bufev, short event);
int bufferevent_disable(struct bufferevent *bufev, short event);
event: EV_READ | EV_WRITE

bufferevent_write

发送数据

int bufferevent_write(struct bufferevent *bufev,const void *data, size_t size);
将data的数据写到buffer_event的写缓冲区中

bufferevent_read

接收数据

size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
将bufferevent的读缓冲区数据读取到data中,
同时将读取到的数据从bufferevent的读缓冲区删除。

evconnlistener_new_bind

连接侦听器,创建套接字、监听并提取

struct evconnlistener *
evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,int socklen)
base: base根节点
cb: 提取套接字cfd后调用的回调typedef void (*evconnlistener_cb)(struct evconnlistener *evl, evutil_socket_t fd, struct sockaddr *cliaddr, int socklen, void *ptr);evl: 链接侦听器的地址fd: cfdcliaddr: 客户端的地址信息socklen: 地址信息长度ptr: 传递给回调函数参数
ptr: 传给回调的参数
flags: LEV_OPT_LEAVE_SOCKETS_BLOCKING 文件描述符为阻塞LEV_OPT_CLOSE_ON_FREE *关闭时自动释放LEV_OPT_REUSEABLE *端口复用LEV_OPT_THREADSAFE 分配锁,线程安全
backlog: -1 自动填充
sa: 绑定的地址信息
socklen: sa的大小
返回值:链接侦听器的地址

bufferevent_socket_connect

封装了底层的socket和connect接口,通过调用此函数将bufferevent事件和通信的socket进行绑定

int bufferevent_socket_connect(struct bufferevent *evl, const struct sockaddr *serv, int scoklen);
evl: 新建的bufferevent节点
serv: 服务器地址
socklen: 服务器长度
1、创建节点 
base = event_base_new();
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct bufferevent *evl = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
struct bufferevent *evl = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
2、封装
bufferevent_socket_connect(evl, serv, socklen);

evconnlistener_free

释放链接监听器

void evconnlistener_free(struct evconnlistener *lev);

bufferevent事件监听流程

  • 创建套接字 socket -> 绑定 bind -> 监听 listen
  • 创建 event_base(event_base_new) -> 初始化上树节点 bufferevent_socket_new
  • 设置回调函数,设置完后会自动上树 bufferevent_setcb 、 设置事件使能 bufferevent_enable、 设置事件不使能 bufferevent_disable
  • 循环监听 event_base_dispatch
  • 其他收尾等 event_base_free、close。

bufferevent实现TCP服务器

参考hello-world.c更改为TCP收发数据

#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_readcb(struct bufferevent *, void *);
static void conn_eventcb(struct bufferevent *, short, void *);
static void signal_cb(evutil_socket_t, short, void *);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);
#endifbase = event_base_new(); // 创建event_base根节点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);// 创建链接监听器 listener_cb监听回调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;}// 创建信号触发节点,收到信号SIGINT,调用信号signal_cbsignal_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;}// 循环监听event_base_dispatch(base);// 释放链接监听器、信号节点、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;// 创建一个bufferevent节点,释放自动关闭bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);if (!bev) {fprintf(stderr, "Error constructing bufferevent!");event_base_loopbreak(base);return;}// 设置回调函数并上树,写回调conn_writecb, 异常事件回调conn_eventcbbufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);bufferevent_enable(bev, EV_WRITE | EV_READ); // 设置读写事件使能// bufferevent_disable(bev, EV_READ); // 设置读时间非使能// 给 cfd 发送消息 MESSAGEbufferevent_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_readcb(struct bufferevent *bev, void *user_data)
{char buff[1500] = "";int n = bufferevent_read(bev, buff, sizeof(buff)); // 读取数据printf("%s\n", buff);bufferevent_write(bev, buff, n); // 发送数据
}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); // 释放bev
}static void
signal_cb(evutil_socket_t sig, short events, void *user_data)
{struct event_base *base = user_data; // 接收传入的base根节点struct timeval delay = { 2, 0 };printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");event_base_loopexit(base, &delay); // 2s后退出循环接听
}

bufferevent实现TCP客户端

可以监听 STDIN 、cfd 、服务器的数据等等

#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;
}

相关文章:

Linux网络编程Socket通信6-Libevent移植与使用

目录 libeventlibevent交叉编译并移植libevent安装安装步骤测试代码libevent执行报错解决 libevent_base根节点event_base_newevent_base_freeevent_reinit event_loop循环等待事件event_base_loopevent_base_dispatchevent_base_loopexitevent_base_loopbreak event事件event_…...

c#:委托 泛型委托的使用 泛型约束

委托 在 C# 中&#xff0c;delegate 是一种引用类型&#xff0c;它允许您定义和使用可以引用特定方法的对象。delegate 可以看作是一种函数指针&#xff0c;它可以在运行时动态地调用不同的方法。 以下是一个简单的例子来说明 delegate 的实际作用&#xff1a; // 1. 定义一…...

大数据之linux入门

一、linux是什么 linux操作系统 开发者是林纳斯-托瓦兹&#xff0c;出于个人爱好编写。linux是一个基于posix和unix的多用户、多任务、支持多线程和多CPU的操作系统。 Unix是20世纪70年代初出现的一个操作系统&#xff0c;除了作为网络操作系统之外&#xff0c;还可以作为单…...

MPI之MPI_Sendrecv接口以及空进程概念介绍

MPI_Sendrecv函数原型 int MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag,void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, MPI_Comm comm, MPI_Status *status);其中各个参数的含义如下&…...

Revit SDK:PointCurveCreation 创建点来拟合曲线

前言 这个例子通过留个例子来展示如何通过点来拟合曲线或者曲面。 内容 PointsParabola 生成抛物线的核心逻辑&#xff1a; double yctr 0; XYZ xyz null; ReferencePoint rp null; double power 1.2; while (power < 1.5){double xctr 0;double zctr 0;while (…...

嵌入式Linux开发实操(十五):nand flash接口开发

# 前言 flash memory,分NAND和NOR: 如果说nor flash有个特点就是能执行代码,NOR并行接口具有地址和数据总线,spi flash更是主要用于存储代码,SPI(或QSPI)NOR代码可就地执行(XiP),一般系统要求flash闪存提供相对较高的频率和数据缓存的clocking。而nand flash主要用于…...

vue2 组件库之vetur提示

当我们开发完自定义UI组件库后&#xff0c;在项目中使用时&#xff0c;想要达到以下提示效果&#xff0c;组件提示与属性提示&#xff0c;有什么解决方案呢&#xff1a; 事实上&#xff0c;这是vetur的功能&#xff0c;原文如下&#xff1a; Component Data | Vetur If a pac…...

慕课网 Go工程师 第三周 package和gomodules章节

Go包的引入&#xff1a; 包名前面加匿名&#xff0c;只引入但不使用&#xff0c;如果对应包有init函数&#xff0c;会执行init函数&#xff08;初始化操作&#xff09; 包名前面加. 把这个包的结构体和方法导入当前包&#xff0c;慎用&#xff0c;你不知道当前包和被引入的包用…...

【ES6】JavaScript 中的数组方法reduce

reduce() 是一个 JavaScript 中的数组方法&#xff0c;它会对数组的每个元素执行一个提供的 reducer 函数&#xff0c;将其减少到一个单一的值。 这是 reduce() 的基本用法&#xff1a; //(method) Array<number>.reduce(callbackfn: (previousValue: number, currentV…...

数据结构--树4.2(二叉树)

目录 一、二叉树的定义和特点 1、定义 2、特点 二、二叉树的基本形态 1、空二叉树 2、只有一个根结点 3、根结点只有左子树 4、根结点只有右子树 5、根结点既有左子树又有右子树 6、斜树 7、满二叉树 8、满二叉树和完全二叉树 三、二叉树的性质 一、二叉树的定义和…...

详解Numpy(基于jupyter notbook)

详解Numpy&#xff08;基于jupyter notbook&#xff09; 1.创建数组2.数据类型3.数组切片和索引4.Numpy的广播与数组操作5.数组合并与通用函数6.其他通用函数 1.创建数组 #引入numpy包&#xff0c;以后np就代表numpy import numpy as npanp.arange(10,30,2)#10为起点&#xff…...

uniapp实现:点击拨打电话,弹出电话号码列表,可以选择其中一个进行拨打

一、实现效果&#xff1a; 二、代码实现&#xff1a; 在uni-app中&#xff0c;使用uni.showActionSheet方法实现点击拨打电话的功能&#xff0c;并弹出相关的电话列表供用户选择。 当用户选择了其中一个电话后&#xff0c;会触发success回调函数&#xff0c;并通过res.tapInde…...

swc-loader Segmentation fault “$NODE_EXE“ “$NPM_CLI_JS“ “$@“

webpack swc swc还不是很稳定。 在swcrc 中有配置plugins 时&#xff0c;swc 转换 /node_modules/ 会报错。 环境 swc/cor1.3.62swc-loader0.2.3swc-plugin-vue-jsx0.2.5 解决 配两套rule,一套处理项目代码&#xff0c;一套处理node_modules webpack.config.js rules:…...

Leetcode78. 子集

给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 回溯法 class Solution {public List<List<Integer>> subsets(int[] nums) {List…...

百度“AI智障”到AI智能体验之旅

目录 前言一、百度PLATO1.抬杠第一名2.听Ta瞎扯淡3.TA当场去世了4.智障与网友的高光时刻 二、文心一言1.设计测试用例2.随意发问3.手机端约会神器 三、体验总结&#xff1a;四、千帆大模型 前言 最近收到了文心一言3.5大模型的内测资格&#xff0c;正巧之前也体验过它的前身&q…...

R中当并行运算遇到C++函数时,让foreach+Rcpp一起工作

目录 方案一&#xff1a;C函数在R包中 方案二&#xff1a;C函数在本地&#xff0c;通过Rcpp::sourceCpp("fun_name.cpp")使用 方案三&#xff1a;将C函数写在当前脚本中 题外话&#xff1a;为什么要研究foreachRcpp? 本文参考&#xff1a; 问题&#xff1a;在fo…...

实现带头双向循环链表

&#x1f308;带头双向循环链表 描述&#xff1a;一个节点内包含两个指针&#xff0c;一个指向上一个节点&#xff0c;另一个指向下一个节点。哨兵位指向的下一个节点为头节点&#xff0c;哨兵位的上一个指向尾节点。 结构优势&#xff1a;高效率找尾节点&#xff1b;高效率插入…...

Mysql 表字符集变更

背景 线上有几张表的字符集是 latin1&#xff0c;要求换成utf8mb4。至于操作的时机则需要自行判断。 1.查看库中所有字符集为latin1的所有表 SELECTDISTINCTtable_schema,table_name,collation_name,character_set_name,CONCAT(ALTER TABLE , table_schema, ., table_name, …...

golang抓取tcp包的实现

要抓取 TCP 请求的数据包&#xff0c;你可以使用 golang 中的 packet 库和 pcap 库。下面是一种使用这些库来抓取 TCP 数据包的方法&#xff1a; 首先&#xff0c;确保已经安装了 pcap 库&#xff0c;可以使用以下命令来安装&#xff1a; go get -u github.com/google/gopack…...

oauth2.0第2季 分布式认证与授权实现单点登录

一 oauth介绍 1.0 疑问汇总 1.使用jwttoken进行令牌传输&#xff0c;资源服务器在本地怎么验证token&#xff1f; 1.1 oauth的基础内容 1.1.1 oauth是什么 1.1.2 oauth的角色 1.1.3 oauth的认证流程 1.1.4 oauth的4种模式 1.2 为何要用oauth2.0 1.介绍单体架构 使用ses…...

SpringBoot一些困惑及梳理

Spring中常用的classpath前缀到底指向哪里? classpath实际就是和java命令行运行时指定的classpath是同一个概念&#xff0c;在ideamaven中也就是指向target/classes目录。不要被网上哪些复制粘贴的文章所迷惑。classpath: 和 classpath*: 到底什么区别? classpath: 实际就是当…...

PostgreSQL汉字转拼音首字母

PostgreSQL汉字转拼音首字母&#xff0c;最近有个需求要做搜索优化&#xff0c;要求提取汉字首字母识别输入&#xff0c;图方便直接数据库用函数批量转换了&#xff0c;整理了网上的两个方法函数备忘&#xff0c;非原创。 https://blog.qdac.cc/?p1281 https://developer.aliy…...

HBuilderX修改manifest.json设置,解决跨域问题(CORS、Cross-Origin)

搭建一个前台uniapp&#xff0c;后台springboot的开发环境时&#xff0c;遇到了跨域问题。 console提示错误信息&#xff1a; Access to XMLHttpRequest at http://10.0.180.203/api/cms/getAdList?apId1 from origin http://localhost:8080 has been blocked by CORS policy…...

AR地图微信小程序:数字化时代下地图应用的新突破

随着数字化时代的到来&#xff0c;地图应用成为人们日常生活中不可或缺的工具。而随着增强现实&#xff08;AR&#xff09;技术的快速发展&#xff0c;AR地图微信小程序应运而生&#xff0c;为用户提供了一种全新的地图导航体验。本文将深入探讨AR地图微信小程序的专业性和思考…...

成集云 | 抖店客户静默下单催付数据同步钉钉 | 解决方案

源系统成集云目标系统 方案介绍 随着各品牌全渠道铺货&#xff0c;主播在平台上直播时客户下了订单后不能及时付款&#xff0c;第一时间客户收不到提醒&#xff0c;不仅造成了客户付款率下降&#xff0c;更大量消耗了企业的人力成本和经济。而成集云与钉钉深度合作&#xff0…...

C++中的运算符总结(5):按位逻辑运算符

C中的运算符总结&#xff08;5&#xff09;&#xff1a;按位逻辑运算符 9、按位运算符 NOT&#xff08; &#xff5e;&#xff09;、 AND&#xff08; &&#xff09;、 OR&#xff08; |&#xff09;和 XOR&#xff08; ^&#xff09; 逻辑运算符和按位运算符之前的差别在…...

《异常检测——从经典算法到深度学习》22 Kontrast: 通过自监督对比学习识别软件变更中的错误

《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …...

大数据风控介绍

众所周知&#xff0c;金融是数据化程度最高的行业之一&#xff0c;也是人工智能和大数据技术重要的应用领域。随着大数据收集、存储、分析和模型技术日益成熟&#xff0c;大数据技术逐渐应用到金融风控的各个环节。个推作为专业的数据智能服务商&#xff0c;拥有海量数据资源&a…...

Linux内核学习(九)—— 虚拟文件系统(基于Linux 2.6内核)

虚拟文件系统&#xff08;VFS&#xff09;作为内核子系统&#xff0c;为用户空间程序提供了文件和文件系统相关的接口。通过虚拟文件系统&#xff0c;程序可以利用标准的 Unix 系统调用对不同的文件系统&#xff08;甚至不同介质上的文件系统&#xff09;进行读写操作。 一、通…...

【模拟】算法实战

文章目录 一、算法原理二、算法实战1. leetcode1576 替换所有的问号2. leetcode495 提莫攻击3. leetcode6 N字形变换4. leetcode38 外观数列5. leetcode1419 数青蛙 三、总结 一、算法原理 模拟就是用计算机来模拟题目中要求的操作&#xff0c;模拟题目通常具有代码量大、操作…...

各个微服务模块之间互相依赖调用的问题

首先是模块之间不能够循环引用&#xff0c;否则会报循环依赖引入的错误。 没有了模块之间的相互依赖&#xff0c;在项目中这两个模块是相互调用的&#xff0c;分别各自定义相应的Feign接口&#xff0c;如下&#xff1a; 最开始写的运行报错的代码如下&#xff1a; FeignCli…...

理论转换实践之keepalived+nginx实现HA

背景&#xff1a; keepalivednginx实现ha是网站和应用服务器常用的方法&#xff0c;之前项目中单独用nginx实现过负载均衡和服务转发&#xff0c;keepalived一直停留在理论节点&#xff0c;加之最近工作编写的一个技术文档用到keepalived&#xff0c;于是便有了下文。 服务组件…...

华为OD七日集训第1期复盘 - 按算法分类,由易到难,循序渐进,玩转OD(文末送书)

目录 一、活动内容如下第1天、逻辑分析第2天、字符串处理第3天、数据结构第4天、双指针第5天、递归回溯第6天、二分查找第7天、贪心算法 && 二叉树 二、可观测性工程1、简介2、主要内容 大家好&#xff0c;我是哪吒。 最近一直在刷华为OD机试的算法题&#xff0c;坚持…...

MPI之持久化通信句柄与非持久化通信句柄

MPI_Isend & MPI_Send 创建临时通信句柄 在前面的文章中举了例子&#xff0c;我们使用MPI_Isend接口发送数据时&#xff0c;有个传出参数request&#xff0c;该参数是创建的通信句柄&#xff0c; 实际上该句柄是一个临时句柄&#xff0c;即只用于一次性发送数据的场景&…...

搭建个人备忘录中心服务memos、轻量级笔记服务

目录 一、源码 二、官网 三、搭建 四、使用 一、源码 GitHub - usememos/memos: A privacy-first, lightweight note-taking service. Easily capture and share your great thoughts. 二、官网 memos - Easily capture and share your great thoughts 三、搭建 docke…...

探究代理技术在网络安全、爬虫与HTTP通信中的多重应用

在当今高度互联的世界中&#xff0c;代理技术在网络安全、爬虫开发以及HTTP通信中扮演着举足轻重的角色。本文将深入探讨Socks5代理、IP代理以及HTTP代理在这些领域中的多重应用&#xff0c;探索其如何为我们创造更安全、高效的网络环境。 1. Socks5代理&#xff1a;构建安全通…...

vue左侧漏斗切换 echart图表动态更新

这个需求是根据点击左侧的箭头部分&#xff0c;右侧图表切换&#xff0c;左侧选中数据高亮&#xff08;图片用的svg&#xff09; 一、效果图 二、vue组件 <template><div class"funnel_wrap"><div class"flex_between"><div class&q…...

Centos7安装ZK-UI管理界面安装|Maven|Git|

一: JDK1.8安装 参考: Centos7卸载|安装JDK1.8|Xshell7批量控制多个终端 二&#xff1a;Maven安装 2.1&#xff1a;下载maven安装包 maven 下载地址&#xff1a;https://mirror.bit.edu.cn/apache/maven/maven-3/ [rootwww ~]# mkdir -p /usr/local/maven [rootwww ~]# …...

C语言日常刷题7

文章目录 题目答案与解析1234567 题目 1、如下程序的运行结果是&#xff08; &#xff09; char c[5]{a, b, \0, c, \0}; printf("%s", c)A: ‘a’ ‘b’ B: ab\0c\0 C: ab c D: ab 2、若有定义&#xff1a; int a[2][3]; &#xff0c;以下选项中对 a 数组元素正确…...

037 - 有关时间和日期的函数方法

文档&#xff1a;MySQL :: MySQL 5.7 Reference Manual :: 12.7 Date and Time Functions​​​​​​ 以下为案例&#xff0c;更多内容可查看文档 返回当前日期&#xff1a; CURDATE() 返回当前时间&#xff1a; CURTIME() 返回当前日期和时间&#xff1a; NOW() 返回年份&a…...

(JAVA)树——tree

...

js判断对象是否为空对象的方法总结

js判断对象是否为空对象的方法总结 方法1&#xff1a;JSON.stringify()方法方法2&#xff1a;for in方法方法3&#xff1a;Object.keys()方法方法4&#xff1a;Object.getOwnPropertyNames()方法方法5&#xff1a;jquery 的 isEmptyObject()方法 在面试或者开发过程中&#xff…...

LeetCode1049. 最后一块石头的重量 II

1049. 最后一块石头的重量 II 文章目录 [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii/)一、题目二、题解方法一&#xff1a;01背包二维数组算法思路具体实现 方法二&#xff1a;01背包一维数组 一、题目 有一堆石头&#xff0c;用整数数…...

universal robot 机械臂 官方基本教程

https://academy.universal-robots.cn/modules/e-Series-core-track/Chinese/module3/story_html5.html?courseId2166&languageChinese 教程1 控制箱内部 包含&#xff1a; 主机板&#xff0c;SD卡&#xff0c;和安全控制板 安全控制板负责所有控制信息&#xff0c;包括…...

网络常见安全漏洞

引言 随着互联网的迅猛发展&#xff0c;网络安全问题日益严重。在网络世界中&#xff0c;各种常见的安全漏洞给人们的通信和数据安全带来了巨大的威胁。本文将介绍一些常见的网络安全漏洞&#xff0c;并提供一些防范措施。 1. XSS&#xff08;跨站脚本攻击&#xff09; 跨站…...

【JS案例】JS实现图片放大镜功能

JS案例图片放大镜 &#x1f31f;效果展示 &#x1f31f;HTML结构 &#x1f31f;CSS样式 &#x1f31f;实现思路 &#x1f31f;具体实现 1.初始化数据图片 2.获取所需DOM元素 3.初始化页面 初始化缩略图 绑定事件 &#x1f31f;完整代码 &#x1f31f;写在最后 &…...

linux centos7 bash中字符串反向输出

给定一个字符串&#xff0c;如何反向(倒序)输出&#xff1f; 字符串反转的方法&#xff1a;a.对各个字符位置进行循环调换&#xff08;从原字符串左边取出放在新字符串的右边&#xff1b;从原字符串右边取出放在新字符串的左边&#xff09;。b.对各个字符由水平排列转为垂直排…...

c++:QT day1 认识与学习

...

git rebase和merge区别

一、概述 merge和rebase 标题上的两个命令&#xff1a;merge和rebase都是用来合并分支的。 这里不解释rebase命令&#xff0c;以及两个命令的原理&#xff0c;详细解释参考这里。 下面的内容主要说的是两者在实际操作中的区别。 1.1 什么是分支 分支就是便于多人在同一项目…...

Vue插槽实现商品列表-编辑渲染

商品列表 文章目录 商品列表核心步骤创建组件 1. MyTag组件详细步骤双击显示&#xff0c;自动聚焦失去焦点&#xff0c;隐藏输入框回显标签信息回车修修改内容&#xff0c;同时隐藏输入框 MyTable组件详细步骤1-动态的设置整个表格的数据 &#xff1a; props2-实现自定义结构-插…...