服务器并发编程--libevent

文章目录

  • 一、Libevent概述
    • 1.两个重要的结构体
    • 2.libevent常用接口
  • 二、libevent IO事件
  • 三、libevent信号事件
  • 四、libevent高并发服务器
  • 参考

一、Libevent概述

Libevent 是一个用C语言编写的、轻量级的开源高性能网络库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。
 
  Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。Libevent之于C语言网络编程,类似于Nettty之于Java Web编程。学习Netty的小伙伴,不防看下Libevent的实现,会加深对Netty框架的理解

安装方式(1):

$ apt-get download libevent-dev
$ dpkg -x  libevent-dev_2.1.12-stable-1build3_amd64.deb libevent

安装方式():

  • libevent的download urls
  • github assert

1.两个重要的结构体

struct event-base

  • 事件集合
  • struct event_base用于创建和管理事件循环,而struct event用于表示具体的事件,并与事件循环相关联。
  • struct event_base 代表一个事件处理的基础框架,它负责管理事件循环(event loop),接收事件并将它们分派给相应的事件处理器。
  • struct event_base 实例典型地代表了一个事件驱动程序的运行环境,它可以被视为事件循环的主体。
  • struct event_base 可以支持多种事件驱动的后端(如select、poll、epoll等),因此在创建 struct event_base 实例时,可以指定使用的后端。

struct event

  • 一个事件(可以是一个fd,也可以是一个signal,也可以是一个定时器事件)
  • struct event 包含了事件的相关信息,比如事件类型(读、写、定时器等)、事件触发时需要执行的回调函数等。
  • 当文件描述符上发生关注的事件时,struct event 将通知 struct event_base,然后 struct event_base 将事件分派给相应的事件处理器执行。

两者关系:

  • struct event结构体中有一个指向struct event_base的指针,用于指示该事件所属的事件循环。这样,当事件发生时,事件循环可以根据事件的描述找到相应的回调函数并执行。

2.libevent常用接口

event_init

  • 用于初始化 libevent 的全局状态。在使用 libevent 前调用此函数是必要的步骤,它会进行一些全局状态的初始化工作。

event_base new

  • event_base_new 用于创建一个新的事件基础框架(struct event_base 实例)。
  • 返回的 event_base 实例将用于管理事件循环和事件处理。

event_set

  • event_set 用于设置事件的相关属性,比如事件关联的文件描述符、事件类型、以及事件触发时执行的回调函数。
    这个函数被废弃了,不建议使用,建议使用 event_assign 替代。

event_assign

  • event_assign 用于将事件与指定的 event_base 关联起来,并设置事件的属性。
  • 这个函数类似于 event_set,但是更加灵活,可以避免一些使用上的混淆。

event_add

  • event_add 用于向事件循环中添加一个事件,让它开始监视文件描述符上的事件。
  • 添加事件后,事件循环将开始监视文件描述符,当有事件发生时,会触发事件的回调函数。

evconnlistener_new_bing

  • evconnlistener_new_bind 是用于创建一个监听器(listener)的函数,用于监听指定地址和端口上的连接请求。
  • 当有连接请求到达时,监听器将接受连接并创建一个新的套接字来处理该连接。

二、libevent IO事件

fifo-read.c


#include <event.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

void fifo_read(evutil_socket_t fd, short events, void *arg) {

  char buf[32] = {0};

  int rt = read(fd, buf, sizeof(buf));
  if (-1 == rt) {
    perror("read");
    exit(-1);
  }

  printf("read <%s>\n", buf);
  return;
}

int main() {
  int ret = mkfifo("fifo.tmp", 0700);

  if (-1 == ret) {
    perror("mkfifo");
    exit(-1);
  }

  int fd = open("fifo", O_RDONLY);
  if (-1 == fd) {
    perror("open");
    exit(-1);
  }

  struct event ev;

  event_init();

  event_set(&ev, fd, EV_READ, fifo_read, NULL);

  event_add(&ev, NULL);

  event_dispatch();

  return 0;
}

fifo-write.c



#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main() {
  int fd = open("fifo.tmp", O_WRONLY);
  if (-1 == fd) {
    perror("open");
    exit(-1);
  }

  char buf[32] = {0};

  while (1) {

    scanf("%s", buf);
    int ret = write(fd, buf, sizeof(buf));
    if (-1 == ret) {

      perror("write");
      exit(-1);
    }

    if (!strcmp(buf, "bye")) {
      break;
    }
    memset(buf, 0, sizeof(buf));
  }

  return 0;
}

三、libevent信号事件

signal.c



#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <signal.h>

static int signal_count = 0;

void signal_handler(evutil_socket_t fd, short events, void *args) {
  printf("<sig: %d>\n", fd);

  ++signal_count;

  if (signal_count >= 2) {
    event_del((struct event *)args);
  }
}

int main() {
  struct event_base *base = event_base_new();

  struct event ev;
  event_assign(&ev, base, SIGINT, EV_SIGNAL | EV_PERSIST, signal_handler, &ev);

  event_add(ev, NULL);

  event_base_dispatch();

  event_base_free(base);

  return 0;
}

四、libevent高并发服务器



#include <arpa/inet.h>
#include <cstddef>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/event_compat.h>
#include <event2/listener.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void read_cb(struct bufferevent *bev, void *ctx) {
  char buf[128] = {0};
  size_t ret = bufferevent_read(bev, buf, sizeof(buf));
  if (ret < 0) {
    exit(-1);
  }

  printf("read from: <%d>\n", *(int *)ctx);
}

void event_cb(struct bufferevent *bev, short what, void *ctx) {
  if (what & BEV_EVENT_EOF)
    printf("Client: <d> down", *(int *)ctx);
  bufferevent_free(bev);
}

void listen_cb(struct evconnlistener *listener, evutil_socket_t fd,
               struct sockaddr *addr, int socklen, void *arg)

{
  static int gFd = -1;
  printf("Accept: <%d>\n", fd);

  gFd = fd;

  struct event_base *base = arg;

  struct bufferevent *bev =
      bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
  if (NULL == bev) {
    exit(-1);
  }

  bufferevent_setcb(bev, read_cb, NULL, event_cb, &gFd);

  bufferevent_enable(bev, EV_READ);
}

int main() {
  struct event_base *base = event_base_new();

  if (NULL == base) {
    printf("event_base \n");

    exit(-1);
  }

  struct sockaddr_in server_addr;
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = 8000;
  server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

  struct evconnlistener *listen = evconnlistener_new_bind(
      base, listen_cb, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 10,
      (const struct sockaddr *)&server_addr, sizeof(server_addr));

  event_base_dispatch(base);

  evconnlistener_free(listen);
  event_base_free(base);

  return 0;
}

参考

  • 服务器并发编程–libevent
  • Libevent初探

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(三)JVM实战——对象的内存布局与执行引擎详解

对象的内存布局 对象的实例化 对象的创建方式 - new的方式 - Class的newInstance():反射的方式 - Construct的newInstance() - clone:实现Cloneable接口,默认浅拷贝 - 使用反序列化&#xff1a;将二进制流转化为内存对象 创建对象的步骤 - 判断对象对应的类是否加载、链接、初…

基础I/O--文件系统

文章目录 回顾C文件接口初步理解文件理解文件使用和并认识系统调用open概述标记位传参理解返回值 closewriteread总结 文件描述符fd0&1&2理解 回顾C文件接口 C代码&#xff1a; #include<stdio.h> int main() { FILE *fpfopen("log.txt",&…

08 - 步骤 表输出

简介 表输出&#xff08;Table Output&#xff09;步骤是用于将 Kettle 中的数据写入关系型数据库表的步骤。它允许用户将数据流中的数据插入、更新或删除到目标数据库表中。 使用 场景 我要将处理完的数据流中的sysOrgCode 跟 plateNumber 保存记录到mysql 1、拖拽表输出…

2.VAM新建保存修改场景文件

新建场景 点击返回场景预览 打开游戏的时候&#xff0c;本身就有了一个新场景&#xff0c;因为现在场景里什么也没有&#xff0c;所以是一片黑暗 点击星号打开主菜单会返回主界面 做一个最简单的Helloworld场景 底下有两个模式&#xff0c;游玩模式和编辑模式 编辑场景的时候…

OpenCV如何使用 GDAL 读取地理空间栅格文件(72)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV的周期性噪声去除滤波器(70) 下一篇 :OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 目录 目标 代码&#xff1a; 解释&#xff1a; 如何使用 GDAL 读取栅格数据 注意 …

05_G1垃圾收集器

G1垃圾收集器简介 垃圾优先 Garbage-First&#xff08;G1&#xff09;垃圾收集器面向多处理器机器&#xff0c;适用于大内存场景。它尝试在无需太多配置的情况下实现垃圾收集暂停时间目标&#xff0c;并同时实现高吞吐量。G1旨在通过适用于当前目标应用和环境的功能&#xff0…

go mod

常用命令 初始化模块 go mod init 模块名下载 go.mod 文件中指明的所有依赖 go mod download github.com/gin-gonic/ginv1.9.(依赖路径)依赖对其&#xff08;使引用的都是所依赖的&#xff09; go mod tidy编辑go.mod go mod edit go mod edit -require"github.com/g…

记录几种排序算法

十种常见排序算法可以分类两大类别&#xff1a;比较类排序和非比较类排序。 常见的快速排序、归并排序、堆排序以及冒泡排序等都属于比较类排序算法。比较类排序是通过比较来决定元素间的相对次序&#xff0c;其时间复杂度不能突破 O(nlogn)。在冒泡排序之类的排序中&…

数据结构---时间复杂度+空间复杂度

算法(algorithm)简单说就是解决问题的方法。方法有好坏&#xff0c;同样算法也是&#xff0c;有效率高的算法&#xff0c;也有效率低的算法。衡量算法的好坏一般从时间和空间两个维度衡量&#xff0c;也就是本文要介绍的时间复杂度和空间复杂度。有些时候&#xff0c;时间与空间…

js api part3

环境对象 环境对象&#xff1a; 指的是函数内部特殊的 变量 this &#xff0c; 它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 函数的调用方式不同&#xff0c;this 指代的对象也不同 【谁调用&#xff0c; this 就是…

springboot模块以及非springboot模块构成的多模块maven项目最佳构建方式

文章目录 背景一般的实现使用spring-boot-dependencies 更优雅的实现. 背景 有时候构建一个多模块maven项目其中某一个模块是web-service需要使用spring boot,其他模块跟spring boot 完全无关,本文总结一下在这个场景下maven项目最佳构建方式. 一般的实现 网上应该也看到过很…

智能工业相机哪家好?

一、什么是智能工业相机 在工业自动化的浪潮中&#xff0c;智能工业相机扮演着至关重要的角色。它们如同工业领域的“眼睛”&#xff0c;为生产过程提供精准的视觉监测和数据采集。然而&#xff0c;面对众多的智能工业相机品牌&#xff0c;如何选择一款真正适合的产品成为了众多…

企业开发基础--数据库

今天完成了数据库学习的全部内容&#xff0c;在事务&#xff0c;索引&#xff0c;范式中要有个人逻辑上的理解&#xff0c;也算是卡着点完成了大多数预期&#xff0c;还有一个Java游戏未完成&#xff0c;会后续补上。 之后的一周要完成34道数据库练习题以及JDBC&#xff0c;学…

88、动态规划-乘积最大子数组

思路&#xff1a; 首先使用递归来解&#xff0c;从0开始到N&#xff0c;每次都从index开始到N的求出最大值。然后再次递归index1到N的最大值&#xff0c;再求max。代码如下&#xff1a; // 方法一&#xff1a;使用递归方式找出最大乘积public static int maxProduct(int[] num…

Graph RAG:基于知识图谱的检索增强技术与优势对比

身处信息爆炸时代&#xff0c;如何从海量信息中获取准确全面的搜索结果&#xff0c;并以更直观、可读的方式呈现出来是大家期待达成的目标。传统的搜索增强技术受限于训练文本数量、质量等问题&#xff0c;对于复杂或多义词查询效果不佳&#xff0c;更无法满足 ChatGPT 等大语言…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

C语言实战项目--贪吃蛇

贪吃蛇是久负盛名的游戏之一&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的行列。在编程语言的教学中&#xff0c;我们以贪吃蛇为例&#xff0c;从设计到代码实现来提升大家的编程能⼒和逻辑能⼒。 在本篇讲解中&#xff0c;我们会看到很多陌生的知识&…

牛角源码 | 【独立版】商城盲盒源码带uniapp(H5+小程序+APP三端)全开源

前端uniapp开源代码&#xff0c;可用HBuilder工具无限发行H5、小程序和打包app&#xff0c;后端PHP开源源码&#xff0c;支持二开。 内有安装搭建教程&#xff0c;轻松部署&#xff0c;搭建即可运营&#xff0c;内置永久免费更新地址&#xff0c;后续无忧升级。 下载地址&…

window 安装ai 基础环境(yolo8,训练推理等)

安装步骤: 1. python sdk 3.9以上&#xff1a;选择 3.9.13, 不知道为什么 3.9.0-0a等安装pytorch 不行。 2. 显卡驱动 可以使用驱动精灵 直接安装N 卡推荐 3. 安装机器学习套件CUDA cuda 安装在PyTorch 需要根 PyTorch版本一致&#xff0c;我的 win-srv 最高支持 12.1 …

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(五)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 继续接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 在下面的图片中&#…
最新文章