libev

article/2025/10/8 15:20:09

开始之前先看一下libevent libev libuv,参考附录1.

本着我自己的个性,我喜欢简单的东西,越简单越好,越傻越好,所以在此我考虑libev,只是tmd,libev的官网打不开,真是无语了。

上例子:

buffer.h

 
#include<iostream>
#include<stdio.h>
#include<string.h>
 
using namespace std;
#define default_buf_size 256
class Buffer
{
    public:
        Buffer()
        {
            buf = new char[default_buf_size];
            buflen = default_buf_size;
        }
        ~Buffer()
        {
            delete[] buf;
        }
        void set_write_buf_size(int needsize)
        {
            int buf_size = writeIdx + needsize;
            if(buf_size <= buflen)
                return;                
            if(needsize < readIdx)
            {
                memmove(buf, buf+readIdx, writeIdx-readIdx);
                writeIdx -= readIdx;
                readIdx = 0;
                return;
            }
            while(buflen < buf_size)
                buflen *= 2;
 
            char *oldbuf = buf;
            buf = new char[buflen];
            memcpy(buf, oldbuf+readIdx, writeIdx-readIdx);
            delete[] oldbuf;
            writeIdx -= readIdx;
            readIdx = 0;
            
        }
        int get_readable_size()
        {
            return writeIdx-readIdx;
        }
        int get_writeable_size()
        {
            return buflen-writeIdx;
        }
 
        void writebuf(void *data, int datalen)
        {
            set_write_buf_size(datalen);
            memcpy(buf+writeIdx, data, datalen);
            writeIdx += datalen;
        }
 
        int writeIdx;
        int readIdx;
        int buflen;
        char *buf;
};
 

 

libev_server.cpp:

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include "./libev/ev++.h"
#include "./libev/ev.h"
#include <stdio.h>
#include <linux/tcp.h>
#include "buffer.h"
 
class NetServer{
public:
   NetServer(){ sockfd = -1;}
   ~NetServer(){}
   void start();
   void accept_cb(ev::io &watcher, int revents);
   void read_cb(ev::io &watcher, int revents);
   void write_cb(ev::io &wather, int revents);
   void timer_cb(ev::timer &watcher, int revents);
   void Close();
private:
   int sockfd;
   ev::default_loop loop;
   ev::io read_io;
   ev::io write_io;
   Buffer readbuf;
   Buffer writebuf;
};
 
void NetServer::start()
{
   sockfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
   if(sockfd < 0)
   {
      perror("create socket error");
      exit(0); 
   }
   struct sockaddr_in sddr, cddr;
   sddr.sin_family = AF_INET;
   sddr.sin_addr.s_addr = INADDR_ANY;
   sddr.sin_port = htons(8888);
   
   if(bind(sockfd, (struct sockaddr*)&sddr, sizeof(sddr)) < 0)
   {
       perror("bind error");
       exit(0);
   }
   if(listen(sockfd, 20)<0)
   {
       perror("listen error");
       exit(0);
   }
   ev::io serv_io;
   serv_io.set<NetServer, &NetServer::accept_cb>(this);
   serv_io.start(sockfd, ev::READ);
   std::cout << "server start now...\n";
 
   loop.run(0);
}
 
void NetServer::accept_cb(ev::io &watcher, int revents)
{
    struct sockaddr_in cddr;
    socklen_t cli_len = sizeof(cddr);
    int clifd = -1;
    if(EV_ERROR & revents)
    {
        perror("get valid events");
        return;
    }
    clifd = accept4(watcher.fd, (struct sockaddr*)&cddr, &cli_len, SOCK_NONBLOCK|SOCK_CLOEXEC);
    if(clifd < 0)
        return;
    int one = 1;
    setsockopt(clifd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one));
    read_io.set<NetServer, &NetServer::read_cb>(this);
    write_io.set<NetServer, &NetServer::write_cb>(this);
    read_io.start(clifd, ev::READ);
    write_io.start(clifd, ev::WRITE);
}
 
void NetServer::read_cb(ev::io &watcher, int revents)
{
    readbuf.set_write_buf_size(1);
    int readlen = recv(watcher.fd, readbuf.buf+readbuf.writeIdx, readbuf.get_writeable_size(), 0);
    
    if(readlen < 0)
    {
        if(errno == EAGAIN || errno== EWOULDBLOCK)
            return;
        Close();
        return;
    }
    if(readlen == 0)
    {
        Close();
        return;
    }
    if(readlen > 0)
    {
        //if(readlen == len)
        printf("recv buf:%s\n", readbuf.buf+readbuf.readIdx);
    }
    readbuf.readIdx += readlen;
}
 
void NetServer::write_cb(ev::io &watcher, int revents)
{
 
}
 
void NetServer::Close()
{
    ::close(sockfd);
    sockfd = -1;
}
 
 
int main()
{
    NetServer netServer;
    netServer.start();
    return 0;
}
 

 

 

附录1:

网络库libevent、libev、libuv对比

2017年05月05日 16:42:34

阅读数:24611

Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)

异步事件库本质上是提供异步事件通知(Asynchronous Event Notification,AEN)的。异步事件通知机制就是根据发生的事件,调用相应的回调函数进行处理。

事件(Event):事件是异步事件通知机制的核心,比如fd事件、超时事件、信号事件、定时器事件。有时候也称事件为事件处理器(EventHandler),这个名称更形象,因为Handler本身表示了包含处理所需数据(或数据的地址)和处理的方法(回调函数),更像是面向对象思想中的称谓。

事件循环(EventLoop):等待并分发事件。事件循环用于管理事件。

对于应用程序来说,这些只是异步事件库提供的API,封装了异步事件库跟操作系统的交互,异步事件库会选择一种操作系统提供的机制来实现某一种事件,比如利用Unix/Linux平台的epoll机制实现网络IO事件,在同时存在多种机制可以利用时,异步事件库会采用最优机制。

 

对比下三个库:

libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;

libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;

libuv :开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;

 

在github上的影响力:

可见,目前libuv的影响力最大,其次是libevent,libev关注的人较少。

 

优先级、事件循环、线程安全维度的对比

 

   特性

                       libevent

 libev

 libuv

  

优先级

激活的事件组织在优先级队列中,各类事

件默认的优先级是相同的,可以通过设置

事件的优先级使其优先被处理

也是通过优先级队列来管理激活的时间,

也可以设置事件优先级

没有优先级概念,按照固定的顺序访

问各类事件

 

事件循环    

 

    event_base用于管理事件

激活的事件组织在优先级队列中,各类事件默认的优先级是相同的,

可以通  过设置事件的优先级   使其优先被处理

 

线程安全

event_base和loop都不是线程安全的,一个event_base或loop实例只能在用户的一个线程内访问(一般是主线程),注册到event_base或者loop的event都是串行访问的,即每个执行过程中,会按照优先级顺序访问已经激活的事件,执行其回调函数。所以在仅使用一个event_base或loop的情况下,回调函数的执行不存在并行关系

 

 

 

事件种类

 

type

libevent

libev

libuv

IO

fd

io

fs_event

计时器(mono clock)

timer

timer

timter

计时器(wall clock)

--

periodic

--

信号

signal

signal

signal

进程控制

--

child

process

文件stat

--

stat

fs_poll

每次循环都会执行的Idle事件

--

idle

idle

循环block之前执行

--

prepare

prepare

循环blcck之后执行

--

check

check

嵌套loop

--

embed

--

fork

--

fork

--

loop销毁之前的清理工作

--

cleanup

--

操作另一个线程中的loop

--

async

async

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )


这个对比对于libev和libuv更有意义,对于libevent,很多都是跟其设计思想有关的。 libev中的embed很少用,libuv没有也没关系;cleanup完全可以用libuv中的async_exit来替代;libuv没有fork事件。

 

可移植性

三个库都支持Linux, *BSD, Mac OS X, Solaris, Windows

 

type

libevent

libev

libuv

dev/poll (Solaris)

y

y

y

event ports

y

y

y

kqueue (*BSD)

y

y

y

POSIX select

y

y

y

Windows select

y

y

y

Windows IOCP

y

N

y

poll

y

y

y

epoll

y

y

y

 

对于Unix/Linux平台,没有什么大不同,优先选择epoll,对于windows,libevent、libev都使用select检测和分发事件(不I/O),libuv在windows下使用IOCP。libevent有一个socket handle, 在windows上使用IOCP进行读写。libev没有类似的。但是libevent的IOCP支持也不是很好(性能不高)。所以如果是在windows平台下,使用原生的IOCP进行I/O,或者使用libuv。

 

异步架构程序设计原则

1、回调函数不可以执行过长时间,因为一个loop中可能包含其他事件,尤其是会影响一些准确度要求比较高的timer。

2、尽量采用库中所缓存的时间,有时候需要根据时间差来执行timeout之类的操作。当然能够利用库中的timer最好。

 


http://chatgpt.dhexx.cn/article/n005VKG9.shtml

相关文章

libev:详解

事件库之Libev&#xff08;一&#xff09; 使用Libev Libev的作者写了一份很好的官方Manual,比较的齐全&#xff0c;即介绍了Libev的设计思想&#xff0c;也介绍了基本使用还包括内部各类事件详细介绍。这里略微赘述一下。Libev通过一个 struct ev_loop 结结构表示一个事件驱动…

事件驱动库 libev 使用详解

C/CLinux服务器开发/后台架构师知识体系 libev 是一个通过 C 语言编写的&#xff0c;高性能的事件循环库&#xff0c;支持多种事件类型&#xff0c;与此类似的事件循环库还有 libevent、libubox 等&#xff0c;在此详细介绍下 libev 相关的内容。 简介 这是一个简单而且高性…

数据库和实例

这篇文章跟数据库开发有什么关系呢&#xff1f;我感觉呢只从字面上看确实没有什么关系&#xff0c;可是了解的话跟大牛讨论时他们最起码不会被鄙视、面试时可能也会有用。如果你再深入的钻研下去你就会发现里面的内容好“丰满”。作为一个菜鸟&#xff08;指本人&#xff09;以…

【达梦数据库实例创建】

达梦数据库实例创建 系统环境&#xff1a;银河麒麟V10 数据库版本&#xff1a;dm8 一、创建数据库实例 1.通过命令切换到路径/dm8/tool 2.执行命令进入配置助手 ./dbca.sh 选择一般用途&#xff0c;自动调整数据库性能参数&#xff0c;进行下一步操作&#xff1a; 设置数据…

SQL 经典实例

《SQL经典实例》 1&#xff0c;在WHERE子句中引用别名列 直接引用-报错 把查询包装为一个内嵌视图&#xff0c;这样就可以引用别名列了 select * from ( select sal as salary, comm as commission from emp ) x where salary < 5000同理&#xff1a;当你想在 WHERE 子句中…

SQL示例数据库

在本教程中&#xff0c;我们将向您介绍在整个教程中使用的SQL示例数据库。以下数据库关系图 - HR 示例数据库&#xff1a; 在这个HR 示例数据库有7个表&#xff1a; employees表存储员工的数据信息。 jobs表存储工作数据信息&#xff0c;包括职位和工资范围。 departments表…

数据库案例

目录 微信朋友圈设计 用户及用户关系 发朋友圈 CDN 发布表 相册表 时间线 刷朋友圈 删除、拉黑、标签、不让他看、三天可见该怎么办 谁可以看 标签 第二步的权限控制 评论和赞 微信朋友圈设计 用户及用户关系 肯定有用户表作为基础 用户关系表&#xff0c;用户…

SQL数据库编写及示例

一、 数据库编写 1、数据库常用约束 主键约束: primary key 外键约束: foreign key (references) 唯一值约束: unique 默认值约束: default 检查约束: check 非空约束: not null 标识列: identity 2、创建数据表注意事项 主外键数据类型必须一致 列与列之间用&#xff0c;间隔…

sqlserver:什么是数据库实例?

环境&#xff1a; window server 2019 datacentersqlserver2014 x64 问题&#xff1a; 什么是SQL server实例&#xff1f;数据库的对象架构是怎样设计的&#xff1f; 先把官方的解释贴出来&#xff1a; https://docs.microsoft.com/zh-cn/sql/relational-databases/databases…

【转】数据库设计实例一学习

​​​​​​数据库1​​​​​​​​​​​​​​​​​​​​​对多&#xff0c;1对1&#xff0c;M对N学习 以RBAC为例。​​​​​​​​​​​​​​ 于 RBAC&#xff08;Role-based Access Control&#xff09;权限访问控制。也就是说一个用户可以有多个角色&#xff…

sql server 数据库设计实例

本实例为综合实例,考察数据库原理中的,sql脚本的编写,创建——增删改查,视图和索引的创建等;数据库ER图,关系模式;以及一些高级的应用包括:触发器,函数和存储过程。 (一). 数据库设计题目如下 有一个图书出版发行管理系统,其主要业务规则如下: 一个作者可以编写多…

达梦数据库创建及数据库实例管理

一、配置助手创建和删除数据库 数据库配置助手创建数据库调用 dbca.sh 图形化界面创建数据库&#xff1a;[dmdbaDCA02 tool]$ ./dbca.sh2021-01-11 11:43:45 [com.dameng.dbca.Startup] [INFO] 启动 DBCA 指定数据库名称、实例名称&#xff08;单机情况下数据库和实例名称可以…

MySql 数据库操作实例

MySql 数据库操作实例 案例描述创建插入数据内外连接~问题问题1&#xff1a;查询周星星的成绩问题2&#xff1a;查询所有人的平均成绩以及其他信息1&#xff09;查询所有人的平均成绩2&#xff09;查询平均成绩最高的前三名3&#xff09;查询平均成绩排名第三的学生信息 问题3&…

数据库五个经典实例

创建数据库链接&#xff0c;需要用到connection对象&#xff0c;recordset对象。 对数据库进行操作&#xff0c;需要用到command对象&#xff0c;parameter对象。这两个对象成对出现。 connection对象&#xff1a;创建数据库链接。在对数据库进行操作的前提步骤。 recordset…

Oracle 数据库实例介绍

文章目录 数据库实例介绍实例结构实例配置读写实例与只读实例实例生命周期实例标识Oracle 根目录Oracle 主目录Oracle SID 实例启动与关闭启动实例与数据库管理员登录启动实例加载数据库打开数据库只读模式数据库文件检查 关闭数据库与实例关闭模式关闭数据库正常关闭异常关闭 …

Python:二叉树遍历

二叉树遍历共有四种方法&#xff0c;分别是前序遍历、中序遍历、后序遍历和层次遍历。 前序遍历&#xff1a; 父节点——左孩子——右孩子 中序遍历&#xff1a;左孩子——父节点——右孩子 后序遍历&#xff1a;左孩子——右孩子——父节点 层次遍历&#xff1a;利用队列解…

【算法】二叉树遍历的几种常见方法

二叉树遍历的几种常见方法 一. 二叉树分类&#xff1a; 完全二叉树满二叉树扩充二叉树平衡二叉树 二. 二叉树的四种遍历方式&#xff1a; 前序遍历&#xff08;先根&#xff0c;再左&#xff0c;最后右&#xff09;中序遍历&#xff08;先左&#xff0c;再根&#xff0c;最…

二叉树遍历的非递归算法

非递归的算法主要采用的是循环出栈入栈来实现对二叉树的遍历&#xff0c;下面是过程分析 以下列二叉树为例&#xff1a;&#xff08;图片来自懒猫老师《数据结构》课程相关内容&#xff09; 1.前序遍历 前序遍历的顺序为&#xff1a;根结点->左子树->右子树 基本过程&a…

二叉树的中序遍历算法

一&#xff0c;简介 二叉树的中序遍历在计算机行业有着重要的作用&#xff0c;其中一个应用就是判断一棵二叉树是否二叉排序树。 下面介绍递归和非递归两种方式实现中序遍历。 二&#xff0c;递归实现 递归实现非常简单&#xff0c;左根右依次进行即可。 void mid_scan2(n…

JavaScript算法 — 二叉树遍历

目录 1、构造二叉树2、递归遍历3、非递归遍历3.1 先序3.2 中序3.3 后序 1、构造二叉树 树节点&#xff1a; // 二叉树节点的构造函数 function TreeNode(val, left, right) {this.val (valundefined ? 0 : val)this.left (leftundefined ? null : left)this.right (righ…