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# 中,delegate 是一种引用类型,它允许您定义和使用可以引用特定方法的对象。delegate 可以看作是一种函数指针,它可以在运行时动态地调用不同的方法。 以下是一个简单的例子来说明 delegate 的实际作用: // 1. 定义一…...

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

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 生成抛物线的核心逻辑: 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组件库后,在项目中使用时,想要达到以下提示效果,组件提示与属性提示,有什么解决方案呢: 事实上,这是vetur的功能,原文如下: Component Data | Vetur If a pac…...

慕课网 Go工程师 第三周 package和gomodules章节
Go包的引入: 包名前面加匿名,只引入但不使用,如果对应包有init函数,会执行init函数(初始化操作) 包名前面加. 把这个包的结构体和方法导入当前包,慎用,你不知道当前包和被引入的包用…...

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

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

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

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

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

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

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

R中当并行运算遇到C++函数时,让foreach+Rcpp一起工作
目录 方案一:C函数在R包中 方案二:C函数在本地,通过Rcpp::sourceCpp("fun_name.cpp")使用 方案三:将C函数写在当前脚本中 题外话:为什么要研究foreachRcpp? 本文参考: 问题:在fo…...

实现带头双向循环链表
🌈带头双向循环链表 描述:一个节点内包含两个指针,一个指向上一个节点,另一个指向下一个节点。哨兵位指向的下一个节点为头节点,哨兵位的上一个指向尾节点。 结构优势:高效率找尾节点;高效率插入…...

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

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

oauth2.0第2季 分布式认证与授权实现单点登录
一 oauth介绍 1.0 疑问汇总 1.使用jwttoken进行令牌传输,资源服务器在本地怎么验证token? 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是同一个概念,在ideamaven中也就是指向target/classes目录。不要被网上哪些复制粘贴的文章所迷惑。classpath: 和 classpath*: 到底什么区别? classpath: 实际就是当…...

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

HBuilderX修改manifest.json设置,解决跨域问题(CORS、Cross-Origin)
搭建一个前台uniapp,后台springboot的开发环境时,遇到了跨域问题。 console提示错误信息: 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地图微信小程序:数字化时代下地图应用的新突破
随着数字化时代的到来,地图应用成为人们日常生活中不可或缺的工具。而随着增强现实(AR)技术的快速发展,AR地图微信小程序应运而生,为用户提供了一种全新的地图导航体验。本文将深入探讨AR地图微信小程序的专业性和思考…...

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

C++中的运算符总结(5):按位逻辑运算符
C中的运算符总结(5):按位逻辑运算符 9、按位运算符 NOT( ~)、 AND( &)、 OR( |)和 XOR( ^) 逻辑运算符和按位运算符之前的差别在…...

《异常检测——从经典算法到深度学习》22 Kontrast: 通过自监督对比学习识别软件变更中的错误
《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …...

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

Linux内核学习(九)—— 虚拟文件系统(基于Linux 2.6内核)
虚拟文件系统(VFS)作为内核子系统,为用户空间程序提供了文件和文件系统相关的接口。通过虚拟文件系统,程序可以利用标准的 Unix 系统调用对不同的文件系统(甚至不同介质上的文件系统)进行读写操作。 一、通…...

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