文章目录

  • 实例一:监控系统登录日志文件
  • 实例二:Echo回显服务实例

实例一:监控系统登录日志文件

在 CentOS7 中,系统登录信息可在文件 /var/log/secure 中查到(其他 Linux 发行版可能有所不同)。本章介绍使用 Libevent 监控这个日志文件,并在有新用户登录时打印输出。

代码比较简单,唯一需要注意的地方就是要使用 event_config_require_features 函数设置支持文件描述符 EV_FEATURE_FDS,具体代码如下:

#include <iostream>
#include "event.h"
#ifndef _WIN32
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endifvoid read_file(evutil_socket_t fd, short event, void *arg) {char buf[1024] = {0};int len = read(fd, buf, sizeof(buf) - 1);if (len > 0) {std::cout << buf << std::endl;}else {// 要有 flush ,否则字符一直在缓存中,不会打印到屏幕std::cout << "." << std::flush;usleep(1000000);}
}int main(int argc, char* argv[])
{#ifdef _WIN32// 初始化 socket 库WSADATA wsa;WSAStartup(MAKEWORD(2, 2), &wsa);
#else// 忽略管道信号,避免程序发生崩溃if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)return -1;
#endifstd::cout << "test libevent monito file!" << std::endl;event_config *cfg = event_config_new();// 设置支持文件描述符event_config_require_features(cfg, EV_FEATURE_FDS);// 创建 libevent 上下文event_base *base = event_base_new_with_config(cfg);event_config_free(cfg);if (!base) {std::cerr << "event_base_new_with_config failed!" << std::endl;return -1;}// 只读,非阻塞打开文件int fd = open("/var/log/secure", O_RDONLY | O_NONBLOCK, 0);if (fd <= 0) {std::cerr << "open /var/log/secure failed!" << std::endl;return -1;}// 文件指针移到结尾lseek(fd, 0, SEEK_END);// 监听文件数据event *ev = event_new(base, fd, EV_READ | EV_PERSIST, read_file, 0);event_add(ev, NULL);// 进入事件主循环event_base_dispatch(base);event_free(ev);event_base_free(base);return 0;
}

运行后,当有用户登录时,则打印登录信息,没有用户登录,则每秒在终端输出一个点。

实例二:Echo回显服务实例

本章使用 Libevent 实现一个 Echo 回显服务实例,这也是网络编程中最常见的实例。为了更基础一些的讲解,这里不是有 Libevent 提供的高级封装接口 evconnlistener_new_bind ,而是使用最基础的 socket 函数。大致步骤如下:

  • 使用 socket 函数建立监听端口,如 socket, bind, listen, accept, recv, send 等;
  • 设置非阻塞和地址复用,使用 Libevent 的封装函数:
  • 监听连接;
  • 客户端通信设置边沿触发,先检测是否支持边沿触发;
  • 客户端设置超时事件,若长时间没有数据,则断开来南京

Echo 回显服务实例代码如下:

#include <iostream>
#include <string.h>
#include <errno.h>
#ifndef _WIN32
#include <signal.h>
#endif // !_WIN32#include "event.h"#define SERVER_PORT 8000// 客户端数据读取事件
void client_cb(evutil_socket_t s, short what, void *arg) {// 水平触发LT:只要有数据没有处理,就会一直触发// 边沿触发ET:只处理一次,不管数据是否处理完event *ev = (event*)arg;// 判断超时if (what & EV_TIMEOUT) {// 需要清理eventstd::cout << "timeout" << std::endl;event_free(ev);evutil_closesocket(s);return;}char buf[1024] = { 0 };// char buf[5] = { 0 };    // 这里是为调试边沿触发,实际使用的缓冲区要大得多int len = recv(s, buf, sizeof(buf) - 1, 0);if (len > 0) {std::cout << buf << std::endl;send(s, "OK", 2, 0);}else {// 需要清理eventstd::cout << "event_free" << std::endl;event_free(ev);evutil_closesocket(s);}
}// 接收连接的回调函数
void listen_cb(evutil_socket_t s, short what, void *arg) {std::cout << "listen_cb" << std::endl;// 读取连接信息sockaddr_in sin;socklen_t len = sizeof(sin);evutil_socket_t client = accept(s, (sockaddr*)&sin, &len);char ip[16] = { 0 };evutil_inet_ntop(AF_INET, &sin.sin_addr, ip, sizeof(ip) - 1);std::cout << "client ip: " << ip << ":" << ntohs(sin.sin_port) << std::endl;// 客户端数据读取事件event_base *base = (event_base*)arg;// 水平触发event* ev = event_new(base, client, EV_READ | EV_PERSIST, client_cb, event_self_cbarg());// 边沿触发,Windows上无效//event* ev = event_new(base, client, EV_READ | EV_PERSIST | EV_ET, client_cb, event_self_cbarg());timeval tv = { 10, 0 };  // 10秒超时event_add(ev, &tv);
}int main(int argc, char* argv[])
{#ifdef _WIN32// 初始化socket库WSADATA wsa;WSAStartup(MAKEWORD(2, 2), &wsa);
#else// 忽略管道信号,因为发送数据给已关闭的socket会生成SIGPIPE信号,导致进程退出if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)return -1;
#endifstd::cout << "libevent echo server test" << std::endl;// 创建libevent上下文event_base *base = event_base_new();if (!base) {std::cout << "event_base_new failed" << std::endl;return -1;}std::cout << "event_base_new success" << std::endl;// 创建 socketevutil_socket_t sock = socket(AF_INET, SOCK_STREAM, 0);if (sock <= 0) {std::cout << "create socket error: " << strerror(errno) << std::endl;return -1;}// 设置非阻塞和地址复用evutil_make_socket_nonblocking(sock);evutil_make_listen_socket_reuseable(sock);// 绑定IP和端口struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(SERVER_PORT);int ret = ::bind(sock, (sockaddr*)&sin, sizeof(sin));if (ret != 0) {std::cout << "bind socket error: " << strerror(errno) << std::endl;return -1;}// 开始监听,建立10个连接的缓存listen(sock, 10);// 创建监听事件,并添加到libevent中event* ev = event_new(base, sock, EV_READ | EV_PERSIST, listen_cb, base);event_add(ev, 0);// 事件分发处理event_base_dispatch(base);// 释放资源event_free(ev);event_base_free(base);#ifdef _WIN32WSACleanup();
#endifreturn 0;
}

注意,代码中有一些测试代码,注释掉了,比如:

  • 第 28 行,将 buf 设置为5,这是为了测试边沿触发,在数据未读完时,水平触发和边沿触发有何不同。实际代码中,不会将缓冲区设得这么小;
  • 第 60 行,设置边沿触发,这需要在 Linux 上测试,在 Windows 上无效。

另外,若是非本机测试,可能会因 centos7 防火墙的原因导致链接无法建立,因为默认未开放 8000 的端口。此时可以使用 iptalbes -F 关闭防火墙,但更高级的做法是使用 firewall-cmd 命令开放 8000 端口:

# 查看开放的端口
[root@localhost ~]# firewall-cmd --list-port
3306/tcp 139/tcp 445/tcp# 开放8000/tpc端口
[root@localhost ~]# firewall-cmd --zone=public --add-port=8000/tcp --permanent
success# 不会立刻生效,需要重新加载防火墙的规则
[root@localhost ~]# firewall-cmd --reload
success
[root@localhost ~]# firewall-cmd --list-port
3306/tcp 139/tcp 445/tcp 8000/tcp

Libevent 学习七:Libevent 两个实例相关推荐

  1. libevent学习__学习历程总结

    The libevent API provides a mechanism to execute a callback function when a specific event occurs on ...

  2. libevent 学习文档-翻译

    文章目录 Libevent 学习记录 第一节 关于文档 第0章:关于本文档 示例说明 第1章:异步IO的简单介绍. 异步 IO 的小介绍 关于便利性?(Windows 呢?) Libevent 参考手 ...

  3. Libevent学习环境搭建

    Libevent 简介 Libevent是一款事件驱动的网络开发包,由于采用C语言开发体积小巧,跨平台,速度极快.大量开源项目使用了Libevent比如谷歌的浏览器和分布式的高速缓存系统memcach ...

  4. libevent学习笔记 一、基础知识

    一.libevent是什么 libevent是一个轻量级的开源的高性能的事件触发的网络库,适用于windows.linux.bsd等多种平台,内部使用select.epoll.kqueue等系统调用管 ...

  5. Libevent 学习一:Libevent 源码编译

    文章目录 Libevent 学习一:Libevent 源码编译 Libevent Windows 编译 Windows 编译环境 安装 Visual Studio Community 2015 安装 ...

  6. libevent学习笔记六:libevent核心事件event

    libevent学习笔记六:libevent核心事件event 前面对reactor模式.事件处理流程.libevent源代码结构等有了高层的认识后,接下来将详细介绍libevent的核心结构even ...

  7. 【Libevent】Libevent学习笔记(一):简介和安装

    00. 目录 文章目录 00. 目录 01. libevent简介 02. Libevent的好处 03. Libevent的安装和测试 04. Libevent成功案例 05. 参考资料 01. l ...

  8. 【传智播客】Libevent学习笔记(一):简介和安装

    目录 00. 目录 01. libevent简介 02. Libevent的好处 03. Libevent的安装和测试 04. Libevent成功案例 00. 目录 @ 01. libevent简介 ...

  9. libevent 学习笔记

    一.参考 libevent Libevent深入浅出 - <Libevent 深入浅出> - 书栈网 · BookStack libevent 之 event config的相关函数介绍_ ...

最新文章

  1. java final private_java – private final static属性vs private final属性
  2. 非常好!!!Linux源代码阅读——环境准备【转】
  3. Interviews(内连接,左外连接,分组、聚合)
  4. PyQt5 技巧篇-参数控制窗体右上角只显示关闭按钮实例演示
  5. JS原型、原型链深入理解
  6. android 框架LoonAndroid,码农偷懒专用(2014/8/6更新)
  7. Java后端:10w行级别数据的Excel导入优化记录
  8. get占位符传多个参数_mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法...
  9. dao-service-servlet-jsp构建简易web通讯录(三层开发)知识点1
  10. SQL获取当前日期函数
  11. python 趋势跟踪算法_DualThrust区间突破策略Python版
  12. 打印机扫描到计算机,打印机扫描文件到电脑方法教程
  13. 3dmax导出unity3d模型设置
  14. JAVA之父,詹姆斯·高斯林传奇人生
  15. 分享一个能对java代码进行“tokenize”的python库
  16. Linux系统管理命令之accton的使用
  17. crm客户管理系统如何助力企业销售管理
  18. 雷达成像原理(一)合成孔径成像Chirp-Scaling
  19. 【LocalDateTime常见用法】
  20. 安卓支持App内文字翻译

热门文章

  1. 江苏2020高中计算机学业水平,2020江苏高中学业水平测试时间安排表
  2. VM虚拟机Ubuntu设置静态IP方法
  3. Android作为HTTP服务器--NanoHTTPD源码分析
  4. 了解标量、向量和点积
  5. 攻防世界之Miscellaneous-300
  6. 动态壁纸android,Android 十大最新版本动态壁纸大盘点
  7. 大数据学习路线,如何学习大数据?
  8. PostgreSQL 12 中文文档
  9. Scalar类-颜色类
  10. iOS 15Beta5版本更新变化,这些细节你发现了吗?