Linux网络编程:libevent事件通知库
文章目录:
一:libevent库
二:libevent框架
1.常规事件event
1.1 创建事件event(event_new)
1.2 添加事件到 event_base(event_add)
1.3 从event_base上摘下事件(event_del)
1.4 销毁事件(event_free)
1.5 未决和非未决
read_fifo.c
write_fifo.c
2.带缓冲区的事件bufferevent
2.1 带缓冲区的事件 bufferevent
2.2 创建、销毁bufferevent(bufferevent_socket_new 、bufferevent_socket_free)
2.3 给bufferevent设置回调(bufferevent_setcb)
2.4 启动、关闭 bufferevent的 缓冲区(bufferevent_enable、bufferevnet_disable)
三:网络通信
1.服务端
1.1 创建和释放监听服务器(evconnlistener_new_bind、evconnlistener_free)
1.2 服务器端 libevent 创建TCP连接流程
ev_server.c
2.客户端
2.1 连接客户端(bufferevent_socket_connect)
2.2 Libevent实现TCP客户端流程
ev_client.c
一:libevent库
libevent官网
libevent库开源;精简;跨平台(Windows、Linux、maxos、unix);专注于网络通信源码包安装: 参考 README、readme./configure 检查安装环境 生成 makefilemake 生成 .o 和 可执行文件sudo make install 将必要的资源cp置系统指定目录进入 sample 目录,运行demo验证库安装使用情况编译使用库的 .c 时,需要加 -levent 选项库名 libevent.so --> /usr/local/lib 查看的到特性:基于“事件”异步通信模型。--- 回调
二:libevent框架
libevent框架:1. 创建 event_base (乐高底座)struct event_base *event_base_new(void);struct event_base *base = event_base_new();2. 创建 事件evnet (积木)常规事件 event --> event_new(); 带缓冲区的事件 bufferevent --> bufferevent_socket_new();3. 将事件 添加到 base上 int event_add(struct event *ev, const struct timeval *tv)4. 循环监听事件满足int event_base_dispatch(struct event_base *base);event_base_dispatch(base);5. 释放 event_baseevent_base_free(base);
1.常规事件event
1.1 创建事件event(event_new)
创建事件event:struct event *ev;struct event *event_new(struct event_base *base,evutil_socket_t fd,short what,event_callback_fn cb; void *arg);base: event_base_new()返回值fd: 绑定到 event 上的 文件描述符what:对应的事件(r、w、e)EV_READ 一次 读事件EV_WRTIE 一次 写事件EV_PERSIST 持续触发。 结合 event_base_dispatch 函数使用,生效cb:一旦事件满足监听条件,回调的函数typedef void (*event_callback_fn)(evutil_socket_t fd, short, void *) arg: 回调的函数的参数返回值:成功创建的 event1.2 添加事件到 event_base(event_add)
添加事件到 event_baseint event_add(struct event *ev, const struct timeval *tv);ev: event_new() 的返回值tv:NULL1.3 从event_base上摘下事件(event_del)
从event_base上摘下事件 【了解】int event_del(struct event *ev);ev: event_new() 的返回值1.4 销毁事件(event_free)
销毁事件int event_free(struct event *ev);ev: event_new() 的返回值1.5 未决和非未决
未决和非未决:非未决: 没有资格被处理未 决:有资格被处理,但尚未被处理event_new --> event ---> 非未决 --> event_add --> 未决 --> dispatch() && 监听事件被触发 --> 激活态 --> 执行回调函数 --> 处理态 --> 非未决 event_add && EV_PERSIST --> 未决 --> event_del --> 非未决
read_fifo.c
#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 read_cb(evutil_socket_t fd, short what, void *arg) {// 读管道char buf[1024] = {0};int len = read(fd, buf, sizeof(buf));printf("read event: %s \n", what & EV_READ ? "Yes" : "No");printf("data len = %d, buf = %s\n", len, buf);sleep(1); }// 读管道 int main(int argc, const char* argv[]) {unlink("myfifo");//创建有名管道mkfifo("myfifo", 0664);// open file//int fd = open("myfifo", O_RDONLY | O_NONBLOCK);int fd = open("myfifo", O_RDONLY);if(fd == -1){perror("open error");exit(1);}// 创建个event_basestruct event_base* base = NULL;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); // while(1) { epoll();}// 释放资源event_free(ev);event_base_free(base);close(fd);return 0; }write_fifo.c
#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; }
2.带缓冲区的事件bufferevent
2.1 带缓冲区的事件 bufferevent
带缓冲区的事件 bufferevent#include <event2/bufferevent.h> read/write 两个缓冲. 借助 队列原理: bufferent利用队列实现两个缓冲区(数据读走就没, FIFO);读: 有数据, 读回调函数被调用, 使用bufferevent_read()读数据;写: 使用bufferevent_write, 向写缓冲中写数据, 该缓冲区中有数据自动写出, 写完后, 回调函数被调用(鸡肋);2.2 创建、销毁bufferevent(bufferevent_socket_new 、bufferevent_socket_free)
创建bufferevent:struct bufferevent* bufferevent_socket_new(struct event_base* base,evutil_socket_t fd,enum bfferevent_options options)base: 基事件, event_base_new函数的返回值;fd:封装到bufferevent内的fd(绑定在一起);enum表示枚举类型, 一般取BEV_OPT_CLOSE_ON_FREE;成功返回bufferevent事件对象;销毁bufferevent:void bufferevent_socket_free(struct bufferevent* ev)2.3 给bufferevent设置回调(bufferevent_setcb)
给bufferevent设置回调:对比event: event_new( fd, callback ); event_add() -- 挂到 event_base 上。bufferevent_socket_new(fd) bufferevent_setcb( callback )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_cb{ bufferevent_read() 读数据 }writecb: 设置 bufferevent 写缓冲,对应回调 write_cb { } -- 给调用者,发送写成功通知。 可以 NULLeventcb: 可传NULL;cbarg: 回调函数的参数;eventcb: 设置 事件回调。 也可传NULLtypedef void (*bufferevent_event_cb)(struct bufferevent *bev, short events, void *ctx);void event_cb(struct bufferevent *bev, short events, void *ctx){。。。。。}events: BEV_EVENT_CONNECTEDread 读回调函数类型(read_cb :bufferevent_read()):typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void*ctx);void read_cb(struct bufferevent *bev, void *cbarg ){.....bufferevent_read(); --- read();}bufferevent_read()函数的原型:size_t bufferevent_read(struct bufferevent *bev, void *buf, size_t bufsize);write 写回调函数类型(bufferevent_write):int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);2.4 启动、关闭 bufferevent的 缓冲区(bufferevent_enable、bufferevnet_disable)
启动、关闭 bufferevent的 缓冲区:void bufferevent_enable(struct bufferevent* bufev,short events); //启用缓冲区void bufferevnet_disable(struct bufferevent* bufev,short events); //禁用 events的值可传入三个宏: EV_READ、EV_WRITE、EV_READ|EV_WRITE默认、write 缓冲是 enable、read 缓冲是 disablebufferevent_enable(evev, EV_READ); -- 开启读缓冲
三:网络通信
1.服务端
1.1 创建和释放监听服务器(evconnlistener_new_bind、evconnlistener_free)
创建监听服务器:------ socket();bind();listen();accept();struct evconnlistener * listner//这一个函数可以完成`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);base: event_basecb: 回调函数。 一旦被回调,说明在其内部应该与客户端完成, 数据读写操作,进行通信ptr: 回调函数的参数flags: LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLEbacklog: listen() 2参。 -1 表最大值sa:服务器自己的地址结构体socklen:服务器自己的地址结构体大小返回值:成功创建的监听器//回调函数的类型typedef void (*evconnlistener_cb)(struct evconnlistener* listener,evutil_socker_t sock,struct sockaddr* addr,int len,void* ptr);listener:evconnlistener_new_bind函数的返回值;sock:用于通信的文件描述符;addr:客户端的地址结构;len:客户端地址结构的长度;ptr:外部ptr传进来的值;释放监听服务器:void evconnlistener_free(struct evconnlistener *lev);1.2 服务器端 libevent 创建TCP连接流程
服务器端 libevent 创建TCP连接:1. 创建event_base2. 创建bufferevent事件对象。bufferevent_socket_new()3. 使用bufferevent_setcb() 函数给 bufferevent的 read、write、event 设置回调函数4. 当监听的 事件满足时,read_cb会被调用, 在其内部 bufferevent_read()读5. 使用 evconnlistener_new_bind 创建监听服务器, 设置其回调函数,当有客户端成功连接时,这个回调函数会被调用6. 封装 listner_cb() 在函数内部。完成与客户端通信7. 设置读缓冲、写缓冲的 使能状态 enable、disable8. 启动循环 event_base_dispath()9. 释放连接
ev_server.c
#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);sleep(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"); }// 被回调,说明有客户端成功连接, cfd已经传入该参数内部。 创建bufferevent事件对象 //与客户端完成读写操作 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;// 通信操作// 创建添加新事件bufferevent 对象struct bufferevent *bev;bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);// 给bufferevent缓冲区设置回调 read、write、eventvoid bufferevent_setcb(struct bufferevent * bufev,bufferevent_data_cb readcb,bufferevent_data_cb writecb,bufferevent_event_cb eventcb,void *cbarg );//设置回调函数bufferevent_setcb(bev, read_cb, write_cb, event_cb,NULL,NULL);//启动 read 缓冲区的 使能状态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);// 创建event_basestruct 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);//销毁event_baseevconnlistener_free(listener);event_base_free(base);return 0; }
2.客户端
2.1 连接客户端(bufferevent_socket_connect)
连接客户端:socket();connect();int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *address, int addrlen);bev: bufferevent 事件对象(封装了fd)address、len:等同于 connect() 参2/32.2 Libevent实现TCP客户端流程
Libevent实现TCP客户端流程1.创建event_basev2.使用bufferevnet_socket_new()创建一个用跟服务器通信的 bufferevnet事件对象3.使用bufferevnet_socket_connect()连接服务器4.使用bufferevent_setcb()给 bufferevnet对象的 read、write、event设置回调5.设置bufferevnet 对象的读写缓冲区enable / disable6.接受、发送数据bufferevent_read() / bufferevent_write()7.启动循环监听event_base_dispatch8.释放资源
ev_client.c
#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网络编程:libevent事件通知库
文章目录: 一:libevent库 二:libevent框架 1.常规事件event 1.1 创建事件event(event_new) 1.2 添加事件到 event_base(event_add) 1.3 从event_base上摘下事件(event_del&a…...
java.lang.reflect.InvocationTargetException:null报未知异常
在项目上线过程中,突然出现大量异常信息,堆栈信息如下: java.lang.reflect.InvocationTargetException: null at jdk .internal.reflect.GeneratedMethodAccessor792 .invoke(Unknown Source) ~[?:?] at jdk.internal.reflect.DelegatingM…...
MySQL高级篇——MySQL架构篇1(Linux下MySQL8的安装与使用)
目录 0 安装前0.1 Linux系统及工具的准备0.2 查看是否安装过MySQL0.3 MySQL的卸载 1 MySQL8的Linux版安装1.1 MySQL的4大版本1.2 下载MySQL指定版本1.3 CentOS7下检查MySQL依赖1.4 CentOS7下MySQL安装过程 2 MySQL登录2.1 首次登录2.2 修改密码2.3 设置远程登录 3 MySQL 8 的密…...
解决 go mod tidy 加载模块超时
如果go mod tidy 加载模块超时 解决方法 修改GOPROXY: 查看go环境相关信息: go envgo env -w GOPROXYhttps://goproxy.cn...
金融市场中的机器学习;快手推出自研语言模型“快意”
🦉 AI新闻 🚀 OpenAI可能面临《纽约时报》的起诉,侵犯知识产权引发争议 摘要:OpenAI使用《纽约时报》的文章和图片来训练AI模型,违反了《纽约时报》的服务条款,可能面临巨大损失。此前,也有其…...
【面试刷题】——什么是深拷贝和浅拷贝?
深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是在编程中用来描述对象拷贝的两个概念,特别是在涉及对象包含其他对象(如嵌套数据结构、指针等)的情况下。 浅拷贝(Shallow Copyÿ…...
物联网(IoT)安全挑战与解决方案: 分析物联网设备面临的安全威胁,以及如何设计和管理安全的IoT生态系统
第一章:引言 随着科技的飞速发展,物联网(IoT)作为连接世界的桥梁,已经成为现代社会不可或缺的一部分。然而,随着IoT设备数量的不断增加,其安全问题也日益显著。本文将深入探讨IoT领域面临的安全…...
Ubuntu 22.04.3 LTS 维护更新发布
近日消息,Canonical 今天发布了代号为 Jammy Jellyfish、长期支持的 Ubuntu 22.04 第 3 个维护版本更新,距离上个版本相隔 6 周时间。 Ubuntu 22.04.3 LTS 最大的亮点在于内核升级到 Linux Kernel 6.2,此外 Mesa 图形堆栈也升级到 23.0.4 版…...
平安健康,找到了医疗服务的价值密码
健康是人类的永恒需求,围绕医疗和健康服务衍生的产业,却苦于无法和用户建立足够紧密、长期的联系。由此,也不得不面临价值从何而来的问题。 作为医疗服务领域的代表性企业,平安健康医疗科技有限公司(股票简称“平安好…...
❤ vue 使用原生组件
❤ vue 使用原生组件 1、做一个input输入框验证开始 ① 想让我们的input输入框类型为时间,只需要为我们的输入框简单的加一个类型的type即可 <input type"date" id"birthday" name"birthday" placeholder"年/月/日"&…...
4.12 TCP 连接,一端断电和进程崩溃有什么区别?
目录 TCP keepalive TCP 的保活机制 主机崩溃 进程崩溃 有数据传输的场景 客户端主机宕机,又迅速重启 客户端主机宕机,一直没有重启 TCP连接服务器宕机和进程退出情况总结 TCP keepalive TCP 的保活机制 TCP 保活机制需要通过 socket 接口设置 S…...
十二、pikachu之URL重定向
文章目录 1、URL重定向概述2、实战3、URL跳转的几种方式:3.1 META标签内跳转3.2 javascript跳转3.3 header头跳转 1、URL重定向概述 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。如果后端采用了前端传进来的(可能是用户传参,或者之前预埋…...
贝叶斯公式中的动词 命名技巧
一项血液化验有95%的把我诊断某种疾病,但是,这项化验用于健康人也会有1%的“伪阳性”结果(即如果一个健康人接受这项化验,则化验结果乌镇此人患有该疾病的概率是0.01)。如果该疾病的患者事实上只占总人口的0.5%,若某人化验结果为阳…...
ctfshow-web13 文件上传
0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 首先看到是一个上传页面,测试其他无果,遂进行目录遍历,发现upload.php.bak文件 可以看到这里的限制条件,大小,以及内容,这里可以使用.use…...
Python项目开发案例————学生信息管理系统(附源码)
一、学生信息管理系统 本文使用Python语言开发了一个学生信息管理系统,该系统可以帮助教师快速录入学生的信息,并且对学生的信息进行基本的增、删、改、查操作;还可以实时地将学生的信息保存到磁盘文件中。 1.1 需求分析 为了顺应互联网时代…...
2023-08-25力扣每日一题
链接: 1448. 统计二叉树中好节点的数目 题意: 判断根节点到每个节点X的过程中,如果没有值大于X,则该节点为好节点,求好节点数量 解: 由于求根节点到其他节点的路径,则使用dfs算法ÿ…...
Vue3中的计算属性和属性监听
compute计算属性 Vue3中可以通过 compute进行监听计算属性,他返回的是一个ref的对象,也就是说 通过compuye这种方式计算属性实际上是进行了ref的操作 import { computed } from vue const user reactive({firstName: A,lastName: B }) // 只有getter的…...
微信开发之一键修改群公告的技术实现
简要描述: 设置群公告 请求URL: http://域名地址/setChatRoomAnnouncement 请求方式: POST 请求头Headers: Content-Type:application/jsonAuthorization:login接口返回 参数: 参数名必…...
【git】工作场景中常用的git命令
工作场景中常用的git命令 1. 必备改名改邮箱拉代码下来并且创建新分支git commit回滚某个文件删除分支 工作场景中常用的git命令,记录下来方便调取 1. 必备 改名改邮箱 一般与他人合作,至少你提交的名字得被人熟知或者遵循规范,因此需要更改…...
Vue路由(详解)
目录 路由原理 路由到底有什么作用? 路由安装和使用(vue2) 路由跳转 跳转实例: 路由的传值和取值 传值实例: 查询参和路由参的区别: 嵌套路由 嵌套实例: 路由守卫 守卫实例࿱…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
LangChain【6】之输出解析器:结构化LLM响应的关键工具
文章目录 一 LangChain输出解析器概述1.1 什么是输出解析器?1.2 主要功能与工作原理1.3 常用解析器类型 二 主要输出解析器类型2.1 Pydantic/Json输出解析器2.2 结构化输出解析器2.3 列表解析器2.4 日期解析器2.5 Json输出解析器2.6 xml输出解析器 三 高级使用技巧3…...
英国云服务器上安装宝塔面板(BT Panel)
在英国云服务器上安装宝塔面板(BT Panel) 是完全可行的,尤其适合需要远程管理Linux服务器、快速部署网站、数据库、FTP、SSL证书等服务的用户。宝塔面板以其可视化操作界面和强大的功能广受国内用户欢迎,虽然官方主要面向中国大陆…...
react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)
之前都是使用react-pdf来渲染pdf文件,这次有个需求是要兼容xp环境,xp上chrome最高支持到49,虽然说iframe或者embed都可以实现预览pdf,但为了后续的定制化需求,还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...
初级程序员入门指南
初级程序员入门指南 在数字化浪潮中,编程已然成为极具价值的技能。对于渴望踏入程序员行列的新手而言,明晰入门路径与必备知识是开启征程的关键。本文将为初级程序员提供全面的入门指引。 一、明确学习方向 (一)编程语言抉择 编…...
多模态学习路线(2)——DL基础系列
目录 前言 一、归一化 1. Layer Normalization (LN) 2. Batch Normalization (BN) 3. Instance Normalization (IN) 4. Group Normalization (GN) 5. Root Mean Square Normalization(RMSNorm) 二、激活函数 1. Sigmoid激活函数(二分类&…...

