黑马程序员C语言教程:libevent
libevent使用介绍
libevent使用介绍在linux平台上使用c开发网络程序的同志们一般情况下都对鼎鼎大名的libevent非常的熟悉了。
但是一些新进入此领域的new new people们对此都是一头雾水。
原本的迷茫再加上开源软件一贯的“帮助文件”缺失作风,让我们这些新手们显的非常的无助。
幸好有一些热心的朋友们帮忙,才化险为夷啊!前几天一直在开发一个locker server,虽然公司现有的locker server能很好的运转,但是毕竟是net的,通用性不广,当我们要在linux上开发多集群系统的时候现有的locker server 就未免显得有点捉襟见肘了。
正是在开发locker server的过程中使用到了libevent。
总体上,libevent是很好用的。
一两个函数就能搞定你复杂的网络通讯工作了。
当然了,这句话得用在你使用的是“单线程”的情况下。
虽然在linux系统中,进程的资源和window系统中进程的资源相比轻量级很多,代价也相当的没有那么昂贵,所以很多的软件都是使用“多进程”方式实现的,比如大名鼎鼎的apache。
但是在我们的系统中,我们使用了“单进程多线程”的方式,这样,我们就能在单机上启动多个进程,以达到“伪分布式”的效果来达到测试的目的。
那么这个时候就要注意libevent的使用了,因为对于event_base 来说,不是线程安全的。
也就是说多线程不能share同一个event_base,就算是加锁操作也不行。
那么这个时候就只能采取“单线程单event_base”的策略了。
我的做法是做一个task pool(任务对象池),每个任务会被一个thread执行,当然了,thread肯定也是从thread pool拿出来的,而在task pool 初始化的时候,我就给每个task中的event_base初始化了对象,这样,万事大吉了。
这个地方注意了以后,就开始说网络通讯了。
在使用libevent的时候,触发事件是在接收到网络连接(或者timeout事件超时)的时候。
libevent evthread_use_pthreads -回复
libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动网络库,它提供了一个高效的跨平台的事件驱动模型,用于构建可扩展的网络应用程序。
evthread_use_pthreads 是libevent库中的一个函数,它用于设置使用pthread线程库作为底层的多线程实现。
本文将深入探讨libevent库及其事件驱动模型以及evthread_use_pthreads函数的作用和用法。
一、libevent库和事件驱动模型简介libevent是一个轻量级、高性能、事件驱动的网络库,最初由Nick Mathewson于2000年开发,并在2002年发布。
它的设计目标是提供一个统一的、跨平台的接口,用于处理网络事件和I/O操作,以支持高并发的网络应用程序。
libevent库可以在多个操作系统上运行,包括Windows、Linux、BSD等。
libevent采用了事件驱动的编程模型,通过使用异步的、非阻塞的I/O操作和事件回调机制来处理网络事件。
在传统的阻塞式I/O模型中,每个连接都需要一个独立的线程或进程来处理,当同时有大量的连接时,会消耗大量的系统资源。
而在事件驱动模型中,通过一个主循环不断监听和分发事件,将连接的处理交给事件回调函数,可以大大提高系统的吞吐量和性能。
二、libevent库的特性和用途1. 高性能:libevent采用非阻塞I/O和事件回调机制,能够处理大量的并发连接,实现高性能的网络应用程序。
2. 跨平台:libevent可以在多个操作系统上运行,包括Windows、Linux、BSD、macOS等。
3. 支持多种网络协议:libevent支持多种常用的网络协议,如TCP、UDP、HTTP等,能够满足不同类型的网络应用需求。
4. 支持定时器:libevent提供了定时器功能,可以方便地实现定时任务的调度和执行。
5. 可扩展性:libevent的设计模式允许用户自定义事件源和事件处理器,以满足复杂应用的需求。
黑马程序员C语言教程:深入浅出-服务器高并发库libevent5篇范文
黑马程序员C语言教程:深入浅出-服务器高并发库libevent5篇范文第一篇:黑马程序员C语言教程:深入浅出-服务器高并发库libevent标题:深入浅出-服务器高并发库libevent(二)上一章,我们简单介绍了libevent的环境的安装,和简单的事例。
现在先不要着急分析他的代码,在这里我首先要介绍一个专业名词“Reactor 模式”。
2.1 Reactor的事件处理机制我们应该很清楚函数的调用机制。
1.程序调用函数 2.函数执行3.程序等待函数将结果和控制权返回给程序4.程序继续处理和执行Reactor 被翻译成反应堆,或者反应器。
Re-actor 发音。
他是一种事件驱动机制。
和普通函数调用的不同之处在于,应用程序不是主动的调用某刻API完成处理,而是恰恰相反,reactor逆置了事件的处理流程,应用程序需要提供相应的接口注册到reacotr上。
如果相应的事件发生。
Reacotr将主动调用应用程序注册的接口,这些接口就是我们常常说的“回调函数”。
我们使用libevent框架也就是想利用这个框架去注册相应的事件和回调函数。
当这些事件发生时,libevent会调用这些注册好的回调函数处理相应的事件(I/O读写、定时和信号)通过reactor调用函数,不是你主动去调用函数,而是等着系统调用。
一句话:“不用打电话给我们,我么会打电话通知你”。
举个例子,你去应聘某xx公司,面试结束后。
“普通函数调用机制”公司的HR比较懒,不会记你的联系方式,那咋办,你只能面试完自己打电话问结果。
有没有被录取啊,还是被拒绝了。
“Reacotr”公司的HR就记下了你的联系方式,结果出来后HR会主动打电话通知你。
有没有被录取啊,还是悲剧了。
你不用自己打电话去问,实际上你也不能,你没有HR的联系方式。
2.2 Reactor模式的优点Reactor模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性;2.3 Reactor模式的必备条件1)事件源Linux上是文件描述符,Windows上就是Socket或者Handle 了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
libevent源码分析event_base_dispatch,event_base_lo。。。
libevent源码分析event_base_dispatch,event_base_lo。
接⼝:event_base_dispatch/**Event dispatching loop 事件分配循环This loop will run the event base until either there are no more pending oractive, or until something calls event_base_loopbreak() orevent_base_loopexit().这个循环将会运⾏event base,知道没有等待的或者活动的事件,或者其它的调⽤了event_base_loopbreak()或event_base_loopexit().@param base the event_base structure returned by event_base_new() orevent_base_new_with_config() event_base_new() 或者 event_base_new_with_config() 返回的event_base对象@return 0 if successful, -1 if an error occurred, or 1 if we exited becauseno events were pending or active. 成功返回0,错误返回-1,或者1(当没有等待的或者活动事件时退出,会返回1)@see event_base_loop()*/EVENT2_EXPORT_SYMBOLint event_base_dispatch(struct event_base *base);intevent_base_dispatch(struct event_base *event_base){return (event_base_loop(event_base, 0));}跟踪event_base_loop接⼝/**Wait for events to become active, and run their callbacks.等待events 变成活动的,并运⾏对应的回调函数。
libevent编译
libevent编译
LibEVENT是一款跨平台的基于BSD下的高性能异步事件驱动库,用于解决异步编程难题。
它能够有效地执行异步I/O或时间事件,可极大提高程序的性能,使之变得优雅。
libevent既可以单独使用,也可以与应用程序(比如web服务器)进行集成,可是以模块的方式实现,做到最大的性能。
LibEvent的编译方法简单易行,有基于Linux、Windows、Mac、BSD等不同操作系统的编译工具。
编译分为configure-make-install三步:
首先,确定libevent的源码包路径,使用linux shell命令进行当前路径切换,cmd进行切换;
其次,执行configure脚本,这是一个自动构建libevent库所需的步骤,命令参数格式如./configure,此步负责生成makefile文件;
最后,执行make命令,此步负责根据makefile文件来编译库文件,编译完成后,安装对应的执行文件。
LibEvent的编译相对来说容易,但需要搭配系统环境,无法满足针对每一种操作系统进行定制。
因此,有时候我们可能需要重新编译libevent,以满足自己应用系统的需求,才能达到最佳性能。
libevent中文参考手册
1 typedef void (*event_fatal_cb)(int err); 2 void event_set_fatal_callback(event_fatal_cb cb);
要使用这些函数,首先定义libevent在遇到致命错误时应该调用的函数,将其传递给event_set_fatal_callback()。随后libevent在遇到致命错误时将调用你提供的函 数。
2库
创建libevent时,默认安装下列库: libevent_core:所有核心的事件和缓冲功能,包含了所有的event_base、evbuffer、bufferevent和工具函数。 libevent_extra:定义了程序可能需要,也可能不需要的协议特定功能,包括HTTP、DNS和RPC。 libevent:这个库因为历史原因而存在,它包含libevent_core和libevent_extra的内容。不应该使用这个库,未来版本的libevent可能去掉这个库。 某些平台上可能安装下列库: libevent_pthreads:添加基于pthread可移植线程库的线程和锁定实现。它独立于libevent_core,这样程序使用libevent时就不需要链接到pthread,除非是以多线程方
10 static void write_to_file_cb(int severity, const char *msg)
11 {
12
const char *s;
13
if (!logfile)
14
return;
15
switch (severity) {
16
case _EVENT_LOG_DEBUG: s = "debug"; break;
Libevent单线程C语言
Libevent (单线程)C语言200客户端CPU 88.1%Libevent 4+1线程(event loop per thread) C语言200客户端TPS如下图CPU占用如下图400客户端1000客户端EPOLL(多worker线程,多个线程共享1个epoll,snapshot) C语言CPU 135.6%400客户端1000客户端Mina2(JAVA) 200客户端CPU 254.3%400客户端1000客户端数据汇总:由以上两图可以得出以下结论:1. 从TPS(每秒处理的请求数据上来看),三者没有本质差异,基于JA V A语言的MINA2框架在TPS上绝对不输于C语言EPOLL和LIBEVENT。
2. EPOLL无论在TPS或者CPU占用率方面都占优势。
这是预料之中,毕竟LIBEVENT也好,MINA2也好,在LINUX上面,最终使用也是EPOLL机制,所以只要不犯低级错误,原生的EPOLL在性能和CPU消耗方面必然会占优势。
3. LIBEVENT和MINA2都在EPOLL基础上做了大量的封装工作,比如LIBEVENT的buffer event,Mina2的codec,不可避免造成额外的CPU开销。
其中基于java语言的mina2在CPU 上开销明显大于C语言的其它方案。
甚至有接近2倍的差异。
4. 我们在开发功能复杂的服务器应用之时,一些基本的工作必须要做,比如buffer,比如codec,这些工作我们自己做,或者交由libevent或者mina2来做,始终都要去做,是避免不了的,而且我们自己去实现,本身效率如何也未知。
所以我们才会选择使用更上层的封闭,一方面减少工作量,另一方面,避免无关的错误发生。
从这一点出发,在做技术选型之时,综合取舍,业务简单但对性能极端要求的场景,可以直接用C语言和EPOLL,业务复杂度高工程较大的需求,可以选用JA V A语言和MINA2。
Libevent安装与使用(一)
Libevent安装与使⽤(⼀)What the lowest level of the Libevent API does: Provides a consistent interface to various select() replacements, using the most efficient version available on the computer where it’s running.Libevent安装1. 在官⽹上下载对应版本的包2. tar -zxvf /your path/libevent-xxxx-stable.tar.gz解压3. cd libevent-xxxx-stable4. ./configure5. make && make install6. 在/usr/local/lib⽬录下将动态库的符号连接复制到/usr/lib/(这是为了防⽌在系统找不到库⽂件)headers:event2/event.hevent2/bufferevent.h/**************************************************/evutil_socket_t //socket ⽂件描述符类型int evutil_make_socket_nonblocking(evutil_socket_t sock);It sets O_NONBLOCK on Unixand FIONBIO on Windows.int evutil_make_listen_socket_reuseable(evutil_socket_t sock);It sets SO_REUSEADDR on Unix and does nothing on Windows. /**************************************************/struct event_base *event_base_new(void); The event_base_new() function allocates and returns a new event base with the default settings. It examines the environment variables and returns a pointer to a new event_base. If there is an error, it returns NULL.When choosing among methods, it picks the fastest method that the OS supports.function is declared in <event2/event.h>./**************************************************/void event_base_free(struct event_base *base); When you are finished with an event_base, you can deallocate it with event_base_free().Note that this function does not deallocate any of the events that are currently associated with the event_base, or close any oftheir sockets, or free any of their pointers./**************************************************/#define EVLOOP_ONCE 0x01#define EVLOOP_NONBLOCK 0x02#define EVLOOP_NO_EXIT_ON_EMPTY 0x04int event_base_loop(struct event_base *base, int flags); By default, the event_base_loop() function runs an event_base until there are no more events registered in it. To run the loop,it repeatedly checks whether any of the registered events has triggered (for example, if a read event’s file descriptor is ready to read, or if a timeout event’s timeout is ready to expire). Once this happens, it marks all triggered events as "active", and starts torun them.If EVLOOP_ONCE is set, then the loop will wait until some events become active, then run active events until there are no more to run, then return. IfEVLOOP_NONBLOCK is set, then the loop will not wait for events to trigger: it will only check whether any events are ready to trigger immediately, and run their callbacks if so. Ordinarily, the loop will exit as soon as it has no pending or active events.You can override this behavior by passing the EVLOOP_NO_EXIT_ON_EMPTY flag---for example, if you’re going to be adding events from some other thread. If youdo set EVLOOP_NO_EXIT_ON_EMPTY, the loop will keep running until somebody calls event_base_loopbreak(), or callsevent_base_loopexit(), or an error occurs.When it is done, event_base_loop() returns 0 if it exited normally, -1 if it exited because of some unhandled error in the backend,and 1 if it exited because there were no more pending or active events.伪代码:while (any events are registered with the loop,or EVLOOP_NO_EXIT_ON_EMPTY was set) {if (EVLOOP_NONBLOCK was set, or any events are already active)If any registered events have triggered, mark them active.elseWait until at least one event has triggered, and mark it active.for (p = 0; p < n_priorities; ++p) {if (any event with priority of p is active) {Run all active events with priority of p.break; /* Do not run any events of a less important priority */}}if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)break;}/**************************************************/int event_base_dispatch(struct event_base *base); The event_base_dispatch() call is the same as event_base_loop(), with no flags set. Thus, it keeps running until there are no more registered events or until event_base_loopbreak() or event_base_loopexit() is called./**************************************************/If you want an active event loop to stop running before all events are removed from it, you have two slightly different functionsyou can call.int event_base_loopexit(struct event_base *base, const struct timeval *tv);int event_base_loopbreak(struct event_base *base); The event_base_loopexit() function tells an event_base to stop looping after a given time has elapsed. If the tv argument is NULL, the event_base stops looping without a delay. If the event_base is currently running callbacks for any active events, it will continue running them, and not exit until they have all been run.The event_base_loopbreak() function tells the event_base to exit its loop immediately. It differs from event_base_loopexit(base, NULL) in that if the event_base is currently running callbacks for any active events, it will exit immediately after finishing the one it’s currently processingNote also that event_base_loopexit(base,NULL) and event_base_loopbreak(base) act differently when no event loop is running: loopexit schedules the next instance of the event loop to stop right after the next round of callbacks are run (as if it had been invoked with EVLOOP_ONCE) whereas loopbreak only stops a currently running loop, and has no effect if the event loop isn’t running.Both of these methods return 0 on success and -1 on failure./**************************************************/#define EV_TIMEOUT 0x01 //This flag indicates an event that becomes active after a timeout elapses.#define EV_READ 0x02#define EV_WRITE 0x04#define EV_SIGNAL 0x08 //Used to implement signal detection. See "Constructing signal events"#define EV_PERSIST 0x10 //Indicates that the event is persistent. See "About Event Persistence" below#define EV_ET 0x20 //Indicates that the event should be edge-triggered, if the underlying event_base backend supports edge-triggered events. //This affects the semantics of EV_READ and EV_WRITEtypedef void (*event_callback_fn)(evutil_socket_t, short, void *);struct event *event_new(struct event_base *base, evutil_socket_t fd, short what, event_callback_fn cb, void *arg);The event_new() function tries to allocate and construct a new event for use with base. The what argument is a set of the flags listed above. (Their semantics are described below.) If fd is nonnegative, it is the file that we’ll observe for read or write events. When the event is active, Libevent will invoke the provided cb function, passing it as arguments: the file descriptor fd, a bitfield of all the events that triggered, and the value that was passed in for arg when the function was constructed.On an internal error, or invalid arguments, event_new() will return NULL.All new events are initialized and non-pending. To make an event pending, call event_add() (documented below).To deallocate an event, call event_free(). It is safe to call event_free() on an event that is pending or active: doing so makes the event non-pending and inactive before deallocating it.About Event PersistenceBy default, whenever a pending event becomes active (because its fd is ready to read or write, or because its timeout expires), it becomes non-pending right before its callback is executed. Thus, if you want to make the event pending again, you can call event_add() on it again from inside the callback function.If the EV_PERSIST flag is set on an event, however, the event is persistent. This means that event remains pending even when its callback is activated. If you want to make it non-pending from within its callback, you can call event_del() on it/**************************************************/int event_assign(struct event *event, struct event_base *base, evutil_socket_t fd, short what, void (*callback)(evutil_socket_t, short, void *), void *arg);All the arguments of event_assign() are as for event_new(), except for the event argument, which must point to an uninitialized event. It returns 0 on success, and -1 on an internal error or bad arguments.⽰例:struct event *ev = event_new(NULL, -1, 0, NULL, NULL);event_assign(ev, base, sockfd, EV_READ | EV_PERSIST,socket_read_cb, (void*)ev);/**************************************************/int event_add(struct event *ev, const struct timeval *tv);Calling event_add on a non-pending event makes it pending in its configured base. The function returns 0 on success, and -1 on failure. If tv is NULL, the event is added with no timeout. Otherwise, tv is the size of the timeout in seconds and microseconds.If you call event_add() on an event that is already pending, it will leave it pending, and reschedule it with the provided timeout. If the event is already pending, and you re-add it with the timeout NULL, event_add() will have no effect.Do not set tv to the time at which you want the timeout to run. If you say "tv->tv_sec = time(NULL)+10;" on 1 January 2010,your timeout will wait 40 years, not 10 seconds.正确⽤法:struct timeval ten_sec;ten__sec = 10;ten__usec = 0;event_add(ev, &ten_sec)/**************************************************/int event_del(struct event *ev);Calling event_del on an initialized event makes it non-pending and non-active. If the event was not pending or active, there is no effect. The return value is 0 on success, -1 on failure.If you delete an event after it becomes active but before its callback has a chance to execute, the callback will not be executed. /**************************************************/void *event_self_cbarg();The event_self_cbarg() function returns a "magic" pointer which, when passed as an event callback argument, tells event_new() to create an event receiving itself as its callback argument./**************************************************/#ifdef WIN32int evthread_use_windows_threads(void);#define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED#endif#ifdef _EVENT_HAVE_PTHREADSint evthread_use_pthreads(void);#define EVTHREAD_USE_PTHREADS_IMPLEMENTED#endifIf you are using the pthreads library, or the native Windows threading code, you’re in luck. There are pre-defined functions that will set Libevent up to use the right pthreads or Windows functions for you.Both functions return 0 on success, and -1 on failure./**************************************************/enum event_method_feature{EV_FEATURE_ET = 0x01, //要求⽀持边沿触发的后端EV_FEATURE_O1 = 0x02, //要求添加、删除单个事件,或者确定哪个事件激活的操作是O(1)复杂度的后端EV_FEATURE_FDS = 0x04, //要求⽀持任意⽂件描述符,⽽不仅仅是套接字的后端};int event_config_require_features(struct event_config *cfg,enum event_method_feature feature);//让 libevent不使⽤不能提供所有指定特征的后端int evutil_make_listen_socket_reuseable(evutil_socket_t sock);This function makes sure that the address used by a listener socket will be available to another socket immediately after the socket is closed. (It sets SO_REUSEADDR on Unix and does nothing on Windows. You don’t want to use SO_REUSEADDR on Windows; it means something different there.)/**************************************************/tips: ⾮阻塞IO:如果输⼊操作不能被满⾜(TCP没有⼀个字节到达,UDP没有⼀个数据报可读)则输⼊操作返回-1 并设置EWOULDBLCOK 错误;如果TCP连接被关闭,则输⼊操作返回0;如果UDP收到长度为0的数据报,则输⼊操作返回0; 对于TCP输出操作,如果发送缓冲区没有空间,则返回-1 并设置EWOULDBLCOK错误;如果发动缓冲区有不⾜的空间,则返回内核能够复制到该缓冲区的字节数,即不⾜字节数。
libevent cmake编译
一、概述1.1 libevent是什么1.2 cmake是什么二、libevent的编译2.1 下载libevent源码2.2 解压源码2.3 创建build目录2.4 使用cmake编译libevent2.4.1 cmake命令的基本语法2.4.2 cmake的常用参数2.4.3 选择编译选项2.4.4 开始编译三、常见问题及解决方案3.1 编译过程中遇到的常见问题3.1.1 找不到依赖库3.1.2 编译错误3.2 解决方案3.2.1 安装依赖库3.2.2 检查编译选项3.2.3 查看编译日志四、接口和应用一、概述1.1 libevent是什么在计算机科学领域,libevent是一个开源的事件通知库,它提供了一个简单的、高效的跨评台事件通知接口,用于实现事件驱动的编程。
它常用于网络应用程序的开发,如服务器端开发,网络爬虫等。
1.2 cmake是什么cmake是一个跨评台的、开源的构建系统,它通过一个描述项目的配置文件CMakeLists.txt来管理整个项目的编译过程。
它可以生成各种不同的构建文件,如Makefile、Visual Studio项目文件等。
二、libevent的编译2.1 下载libevent源码我们需要从libevent全球信息站或者其他途径上下载libevent的源码压缩包,通常为.tar.gz或.zip格式。
2.2 解压源码下载完源码之后,我们需要解压缩文件到我们工作目录中。
解压命令如下:tar -zxvf libevent-x.x.x.tar.gz2.3 创建build目录接下来,我们需要在libevent源码目录下创建一个build目录,用于存放编译生成的文件。
可以使用以下命令创建build目录:mkdir buildcd build2.4 使用cmake编译libevent在build目录中,我们使用cmake命令来配置和编译libevent。
下面是一些常用的cmake命令及参数。
Libevent源码分析—event_add()
Libevent源码分析—event_add()接下来就是将已经初始化的event注册到libevent的事件链表上,通过event_add()来实现,源码位于event.c中。
event_add()这个函数主要完成了下⾯⼏件事:1.将event注册到event_base的I/O多路复⽤要监听的事件中2.将event注册到event_base的已注册事件链表中3.如果传⼊了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的⼩根堆中;如果没有传⼊超时时间,则不会添加到⼩根堆中。
只有步骤1成功,才会执⾏步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。
从中还可以看到,将event添加到已注册事件链表、添加到⼩根堆、从活跃事件链表移除、从⼩根堆中移除,都是通过两个函数完成的:event_queue_insert()、event_queue_remove()intevent_add(struct event *ev, const struct timeval *tv){struct event_base *base = ev->ev_base; //event所属的event_baseconst struct eventop *evsel = base->evsel; //event_base的I/O多路复⽤机制void *evbase = base->evbase; //event_base的I/O多路复⽤机制int res = 0;//DEBUG log.hevent_debug(("event_add: event: %p, %s%s%scall %p",ev,ev->ev_events & EV_READ ? "EV_READ " : "",ev->ev_events & EV_WRITE ? "EV_WRITE " : "",tv ? "EV_TIMEOUT " : "",ev->ev_callback));assert(!(ev->ev_flags & ~EVLIST_ALL));/** prepare for timeout insertion further below, if we get a* failure on any step, we should not change any state.*///如果传⼊了超时时间并且event不再time⼩根堆上,则在⼩根堆上预留⼀个位置//以保证如果后⾯有步骤失败,不会改变初始状态,保证是个原⼦操作if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {if (min_heap_reserve(&base->timeheap, //min_heap.h1 + min_heap_size(&base->timeheap)) == -1)return (-1); /* ENOMEM == errno */}//如果event不在已注册链表或活跃链表中,//则调⽤evsel->add()注册event事件到I/O多路复⽤监听的事件上if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {res = evsel->add(evbase, ev); //将event注册到监听事件上//注册监听事件成功,则将event注册到已注册事件链表上if (res != -1)event_queue_insert(base, ev, EVLIST_INSERTED); //插⼊}/** we should change the timout state only if the previous event* addition succeeded.*///前⾯操作都成功情况下,才能执⾏下⾯步骤//改变超时状态if (res != -1 && tv != NULL) {struct timeval now;/** we already reserved memory above for the case where we* are not replacing an exisiting timeout.*///EVLIST_TIMEOUT表明event已在定时器堆中//则删除旧的定时器if (ev->ev_flags & EVLIST_TIMEOUT)event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除/* Check if it is active due to a timeout. Rescheduling* this timeout before the callback can be executed* removes it from the active list. *///如果事件是由于超时⽽变成活跃事件//则从活跃事件链表中删除if ((ev->ev_flags & EVLIST_ACTIVE) &&(ev->ev_res & EV_TIMEOUT)) {/* See if we are just active executing thisif (ev->ev_ncalls && ev->ev_pncalls) {/* Abort loop */*ev->ev_pncalls = 0; //调⽤次数清0}//从活跃事件链表移除event_queue_remove(base, ev, EVLIST_ACTIVE); //移除}gettime(base, &now);evutil_timeradd(&now, tv, &ev->ev_timeout); //为event添加超时时间event_debug(("event_add: timeout in %ld seconds, call %p",tv->tv_sec, ev->ev_callback));//将event插⼊到⼩根堆中event_queue_insert(base, ev, EVLIST_TIMEOUT); //插⼊}return (res);}event_queue_insert()该函数根据不同的输⼊队列,即不同的事件,在不同的队列中插⼊,并增加相应的事件计数,更新event状态;EVLIST_INSERTED:在已注册事件链表event_base.eventqueue插⼊EVLIST_ACTIVE:根据event优先级,在活跃事件链表event_base.activequeues[event.ev_pri]插⼊EVLIST_TIMEOUT:在⼩根堆event_base.timeheap中插⼊voidevent_queue_insert(struct event_base *base, struct event *ev, int queue){//如果event已经在活跃链表中,则返回;否则,出错if (ev->ev_flags & queue) {/* Double insertion is possible for active events */if (queue & EVLIST_ACTIVE)return;event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,ev, ev->ev_fd, queue);}if (~ev->ev_flags & EVLIST_INTERNAL)base->event_count++; //增加注册事件数ev->ev_flags |= queue; //改变event状态switch (queue) { //根据不同的输⼊参数队列,选择在不同的事件集合中插⼊case EVLIST_INSERTED: //I/O或Signal事件TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); //在已注册事件链表插⼊break;case EVLIST_ACTIVE: //活跃事件base->event_count_active++; //增加活跃事件数TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], //在活跃事件链表插⼊ev,ev_active_next);break;case EVLIST_TIMEOUT: { //定时器事件min_heap_push(&base->timeheap, ev); //在⼩根堆插⼊break;}default:event_errx(1, "%s: unknown queue %x", __func__, queue);}}event_queue_remove()和event_queue_insert()相对应,这个函数主要根据不同的输⼊参数,从不同的事件集合中删除事件。
libevent evthread_use_pthreads
libevent evthread_use_pthreads题目:深入探究libevent中的evthread_use_pthreads引言:在计算机领域中,多线程编程是一种常见且重要的技术,在提高程序并发性、提升计算效率方面发挥着关键作用。
libevent是一款广泛应用于网络编程的开源软件库,通过提供事件驱动、可移植的网络服务器和客户端功能,简化了开发者的工作。
本文将着重深入探究libevent中的evthread_use_pthreads函数,这个函数用于在多线程环境中利用pthreads库实现线程并发。
第一部分:libevent概述1.1 何为libevent?libevent是一个开源软件库,为网络应用提供了一个事件驱动编程接口,可用于基于事件的网络服务器和客户端的开发。
它支持多种事件类型,包括套接字、文件、时间以及信号等。
通过使用libevent,开发者可以编写高度并发性的网络服务器,充分利用计算机资源,提高服务器性能。
1.2 libevent的优势- 事件驱动:libevent基于事件回调机制,即在特定事件发生时,自动调用相应函数进行处理。
- 可移植性:libevent采用了模块化设计,并提供了平台无关的API,因此可以轻松移植到不同的操作系统上。
- 高性能:利用事件驱动的方式,libevent可以高效处理大量并发连接,提供了高性能的网络编程能力。
第二部分:evthread_use_pthreads函数介绍2.1 函数定义在libevent中,evthread_use_pthreads函数用于在多线程环境中利用pthreads库实现线程并发。
其定义如下:cint evthread_use_pthreads(void)2.2 函数功能evthread_use_pthreads函数的主要功能是使libevent能够在多线程环境中使用pthreads库提供的线程功能。
通过调用该函数,开发者可以在libevent中使用线程相关的函数和特性。
libevent交叉编译详细过程
libevent交叉编译详细过程一、前言本文将介绍在Linux环境下使用Cygwin和MinGW交叉编译libevent的详细过程,希望能为初学者提供一定的帮助。
二、安装Cygwin和MinGW首先,我们需要在Windows系统下安装两个工具,Cygwin和MinGW,这两个工具分别提供了类Unix环境下的工具集和MinGW编译器。
Cygwin的安装方式可以参考官方文档,这里不再详述,而MinGW的安装方式则可以参考以下步骤:1. 下载MinGW安装包,推荐使用mingw-get-setup.exe下载,这是MinGW官方提供的一种安装方式。
2. 运行mingw-get-setup.exe,并选择需要安装的组件,其中至少需要安装“mingw32-base”和“mingw32-gcc-g++”两个组件。
3. 安装完成后,在系统环境变量中添加MinGW的bin目录,这样就可以使用MinGW编译器了。
三、交叉编译libevent1. 下载libevent源码,并解压缩。
可以从官方网站下载最新版本的源码。
2. 打开Cygwin终端,进入libevent源码目录,并执行以下命令,这将生成适用于MinGW编译器的Makefile文件:./configure --host=i686-pc-mingw323. 接下来,执行make命令进行编译,在Linux环境下编译完成后,我们就可以开始交叉编译了。
执行以下命令:make -j4 CC=i686-pc-mingw32-gcc AR=i686-pc-mingw32-arRANLIB=i686-pc-mingw32-ranlib这条命令中,-j4表示使用4个线程进行编译,CC、AR和RANLIB则分别指定了MinGW的三种工具。
4. 编译完成后,我们需要将生成的库文件和头文件复制到MinGW编译器的目录中,这样就可以在Windows环境下使用libevent库了。
执行以下命令:mkdir -p /mingw/libcp .libs/*.a /mingw/libmkdir -p /mingw/include/eventcp *.h /mingw/include/event四、总结通过本文的介绍,我们可以了解如何在Linux环境下使用Cygwin和MinGW交叉编译libevent库,并将编译结果复制到Windows环境下使用。
libevent evthread_use_pthreads -回复
libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动编程库,用于在网络应用中处理并发事件。
它提供了跨平台的、高性能的事件处理机制,可以用于开发高效的网络服务器和客户端应用程序。
其中的evthread_use_pthreads函数是libevent 库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。
本文将详细介绍libevent和evthread_use_pthreads函数,以及如何使用它来构建高并发的网络应用程序。
一、libevent简介libevent是一个基于事件驱动的编程库,最初由Niels Provos和Nick Mathewson于2000年开发。
它提供了跨平台的API,可以在各种操作系统上运行。
libevent的目标是提供一种简单、高效的方式来处理并发事件,无论是网络应用还是其他类型的应用,都可以通过libevent来实现高性能和可伸缩性。
libevent的核心概念是事件循环(event loop)机制。
在libevent中,所有的I/O操作都被转化为事件,应用程序通过注册回调函数来处理这些事件。
当一个事件发生时,libevent会将其分发给相应的回调函数进行处理。
这种事件驱动的方式使得应用程序可以同时处理多个并发事件,而不需要为每个事件创建一个独立的线程。
libevent提供了一系列的函数和数据结构来支持事件处理。
它可以处理各种类型的事件,包括网络I/O事件、定时器事件、信号事件等。
通过注册合适的回调函数,应用程序可以根据需要处理不同类型的事件。
二、evthread_use_pthreads函数evthread_use_pthreads函数是libevent库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。
具体来说,它将libevent的并发处理模型设置为使用pthread线程库来创建和管理线程。
libevent源码event_config_new(),event_base_new_w。。。
libevent源码event_config_new(),event_base_new_w。
struct event_config *event_config_new(void);/**Allocates a new event configuration object. 分配⼀个新的event_config对象The event configuration object can be used to change the behavior ofan event base. event_config对象可以⽤于更改event base的⾏为@return an event_config object that can be used to store configuration, orNULL if an error is encountered. 返回⼀个event_config 对象,由于存储配置,当发⽣错误返回NULL@see event_base_new_with_config(), event_config_free(), event_config*/struct event_base *event_base_new_with_config(const struct event_config *);/**Initialize the event API. 初始化event接⼝Use event_base_new_with_config() to initialize a new event base, takingthe specified configuration under consideration. The configuration objectcan currently be used to avoid certain event notification mechanisms. 通过event_base_new_with_config(),使⽤指定位置的配置来初始化⼀个新的event base.使⽤的配置对象可⽤于避免默写事件通知机制。
libevent程序开发
一、libevent程序开发1.认识libeventlibevent是一个开源的库;libevent是一个事件触发的网络库;libevent是一个reactor事件驱动机制模型;libevent支持用户使用三种类型的事件,分别是网络IO、定时器、信号三种;适用于windows、linux、bsd等多种平台;内部使用select、epoll、kqueue等系统调用管理事件机制。
著名分布式缓存软件memcached也是libevent based,Google 的chrome浏览器背后的引擎Chromium 也是用了libevent。
而且libevent在使用上可以做到跨平台,而且根据libevent官方网站上公布的数据统计,似乎也有着非凡的性能。
(百度百科)2.组要组成libevent包括事件管理、缓存管理、DNS、HTTP、缓存事件几大部分。
事件管理包括各种IO(socket)、定时器、信号等事件;缓存管理是指evbuffer功能;DNS是libevent提供的一个异步DNS查询功能;HTTP是libevent的一个轻量级http实现,包括服务器和客户端。
libevent也支持ssl,这对于有安全需求的网络程序非常的重要,但是其支持不是很完善,比如http server的实现就不支持ssl。
3.Reactor模型3.1框架概述在Reactor模式中,有5个关键的参与者。
(1)描述符(handle):由操作系统提供,用于识别每一个事件,如Socket描述符、文件描述符等。
在Linux中,它用一个整数来表示。
事件可以来自外部,如来自客户端的连接请求、数据等。
事件也可以来自内部,如定时器事件。
(2)同步事件分离器(demultiplexer):是一个函数,用来等待一个或多个事件的发生。
调用者会被阻塞,直到分离器分离的描述符集上有事件发生。
Linux的select函数是一个经常被使用的分离器。
(3)事件处理器接口(event handler):是由一个或多个模板函数组成的接口。
libevent使用例子从简单到复杂libevent例子
Libevent使用例子,从简单到复杂,libevent例子Libevent使用例子,从简单到复杂,libevent例子转载请注明出处:/luotuo44/article/details/39670221本文从简单到复杂,展示怎么使用Libevent。
另外网上的很多例子都是只有服务器端的,本文里面客户端和服务器端都有。
不说这么多了,直接上代码。
初等:客户端代码:#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<errno.h>#include<unistd.h>#include<stdio.h>#include<string.h>#include<stdlib.h>#include<event.h>#include<event2/util.h>int tcp_connect_server(const char* server_ip, int port);void cmd_msg_cb(int fd, short events, void* arg);void socket_read_cb(int fd, short events, void *arg);int main(int argc, char** argv){if( argc < 3 ){printf("please input 2 parameter\n");return -1;}//两个参数依次是服务器端的IP地址、端口号int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));if( sockfd == -1){perror("tcp_connect error ");return -1;}printf("connect to server successful\n");struct event_base* base = event_base_new();struct event *ev_sockfd = event_new(base, sockfd,EV_READ | EV_PERSIST,socket_read_cb, NULL);event_add(ev_sockfd, NULL);//监听终端输入事件struct event* ev_cmd = event_new(base,STDIN_FILENO,EV_READ | EV_PERSIST, cmd_msg_cb,(void*)&sockfd);event_add(ev_cmd, NULL);event_base_dispatch(base);printf("finished \n");return 0;}void cmd_msg_cb(int fd, short events, void* arg) {char msg[1024];int ret = read(fd, msg, sizeof(msg));if( ret <= 0 ){perror("read fail ");exit(1);}int sockfd = *((int*)arg);//把终端的消息发送给服务器端//为了简单起见,不考虑写一半数据的情况write(sockfd, msg, ret);}void socket_read_cb(int fd, short events, void *arg) {char msg[1024];//为了简单起见,不考虑读一半数据的情况int len = read(fd, msg, sizeof(msg)-1);if( len <= 0 ){perror("read fail ");exit(1);}msg[len] = '\0';printf("recv %s from server\n", msg);}typedef struct sockaddr SA;int tcp_connect_server(const char* server_ip, int port) {int sockfd, status, save_errno;struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr) );server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);status = inet_aton(server_ip,&server_addr.sin_addr);if( status == 0 ) //the server_ip is not valid value{errno = EINVAL;return -1;}sockfd = ::socket(PF_INET, SOCK_STREAM, 0);if( sockfd == -1 )return sockfd;status = ::connect(sockfd, (SA*)&server_addr,sizeof(server_addr) );if( status == -1 ){save_errno = errno;::close(sockfd);errno = save_errno; //the close may be errorreturn -1;}evutil_make_socket_nonblocking(sockfd);return sockfd;}服务器端代码:#include<stdio.h>#include<string.h>#include<errno.h>#include<unistd.h>#include<event.h>void accept_cb(int fd, short events, void* arg);void socket_read_cb(int fd, short events, void *arg);int tcp_server_init(int port, int listen_num);int main(int argc, char** argv){int listener = tcp_server_init(9999, 10);if( listener == -1 ){perror(" tcp_server_init error ");return -1;}struct event_base* base = event_base_new();//添加监听客户端请求连接事件struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,accept_cb, base);event_add(ev_listen, NULL);event_base_dispatch(base);return 0;}void accept_cb(int fd, short events, void* arg){evutil_socket_t sockfd;struct sockaddr_in client;socklen_t len;sockfd = ::accept(fd, (struct sockaddr*)&client, &len );evutil_make_socket_nonblocking(sockfd);printf("accept a client %d\n", sockfd);struct event_base* base = (event_base*)arg;//仅仅是为了动态创建一个event结构体struct event *ev = event_new(NULL, -1, 0, NULL,NULL);//将动态创建的结构体作为event的回调参数event_assign(ev, base, sockfd, EV_READ |EV_PERSIST,socket_read_cb, (void*)ev);event_add(ev, NULL);}void socket_read_cb(int fd, short events, void *arg){char msg[4096];struct event *ev = (struct event*)arg;int len = read(fd, msg, sizeof(msg) - 1); if( len <= 0 ){printf("some error happen when read\n");close(event_get_fd(ev));event_free(ev);return ;}msg[len] = '\0';printf("recv the client msg: %s", msg);char reply_msg[4096] = "I have recvieced the msg: ";strcat(reply_msg + strlen(reply_msg), msg);write(fd, reply_msg, strlen(reply_msg) );}typedef struct sockaddr SA;int tcp_server_init(int port, int listen_num){int errno_save;evutil_socket_t listener;listener = ::socket(AF_INET, SOCK_STREAM, 0);if( listener == -1 )return -1;//允许多次绑定同一个地址。
vc使用libevent网络库
Windows平台下libevent库的使用1 引子手头上有一个使用了4个年头的HttpClient库,自己封装的,对于集成了IE浏览器的应用程序很友好。
但最近想把产品扩展到Chrome和FireFox阵营,萌发了重构HttpClient的想法,自此便再也抑制不住冲动了。
考察了很多的C++网络库,最终选定了libevent,没别的,一开源,二轻量,三没有额外的依赖库,四对VS很友好,喜不自禁。
2 编译2.1 下载从官网/下载了最新的stable代码包(libevent-2.0.21-stable.tar.gz),解压到F:\libevent-2.0.21-stable。
2.2 准备编译直接打开解压目录下的Makefile.nmake,找到:# Needed for correctnessCFLAGS=/IWIN32-Code /Iinclude/Icompat /DWIN32 /DHAVE_CONFIG_H /I.在CFLAGS这一行添加/MT编译命令,修改后如下:CFLAGS=/IWIN32-Code /Iinclude/Icompat /DWIN32 /DHAVE_CONFIG_H /I. /MT其次,找到:LIBFLAGS=/nologo在后面添加NODEFAULTLIB命令,修改然后如下:LIBFLAGS=/nologo/NODEFAULTLIB:"libc.lib"OK,可以保存了。
2.3 编译直接在菜单中找到VS命令行(我用的是VS2003,理论上讲VS2005及以后的版本都是一样的操作):在命令行中,先切换到libevent的解压目录(F:\libevent-2.0.21-stable),然后使用nmake 命令进行编译:nmake /f Makefile.nmake编译完之后,我们要使用的三个库libevent.lib、libevent_core.lib和libevent_extras.lib已经妥妥的生成好了(就在F:\libevent-2.0.21-stable下)。
libevent 编译
libevent 编译libevent 是一个开源的、轻量级的事件驱动库,被广泛用于网络服务器和应用程序开发中。
它提供了一个简单而高效的方式来处理并发网络连接和事件驱动编程。
本文将介绍libevent的基本概念、特性和使用方法。
一、libevent的基本概念1. 事件循环:libevent的核心是事件循环,它负责监听和分发事件。
事件循环可以理解为一个无限循环,不断地等待事件的发生并处理它们。
2. 事件:事件是指一个特定的操作或状态,可以是网络连接建立、数据可读、定时器到期等。
libevent可以监听多种类型的事件,并在事件发生时进行相应的处理。
3. 回调函数:libevent使用回调函数来处理事件。
当某个事件发生时,libevent会调用相应的回调函数来处理该事件。
开发者需要提供回调函数的实现,以定义事件发生时的具体行为。
4. 事件驱动:libevent采用事件驱动的编程模型,即程序通过监听和处理事件来驱动程序的执行。
相比于传统的顺序执行模型,事件驱动模型更加高效和灵活。
二、libevent的特性1. 跨平台:libevent可以在多种操作系统上运行,包括Linux、Windows、MacOS等,具有良好的跨平台性。
2. 高性能:libevent采用非阻塞的IO模型,能够处理大量并发连接,具有出色的性能表现。
3. 多种网络协议支持:libevent支持TCP、UDP、HTTP等多种网络协议,可以满足不同应用场景的需求。
4. 定时器支持:libevent提供了定时器功能,可以方便地实现定时任务的调度。
5. 可扩展性:libevent的设计非常灵活,可以方便地扩展和定制,满足各种复杂的需求。
三、使用libevent进行事件驱动编程1. 初始化libevent:使用event_base_new()函数初始化一个事件基础结构体,并通过event_base_dispatch()函数进入事件循环。
2. 创建事件:使用event_new()函数创建一个事件,并指定事件类型和相关的回调函数。
libevent 编译
Iibevent编译
编译Iibevent库可以按照以下步骤进行:
下载Iibevent源代码:可以从IibeVem官方网站下载最新版本的源代码,也可以使用版本控制工具如Git从GitHub上获取源代码。
解压源代码:将下载的源代码压缩包解压到指定的目录中。
进入解压后的源代码目录:使用命令行终端进入解压后的Iibevent源代码目录。
配置编译选项:执行以下命令进行配置:
./configure
可以根据需要添加一些编译选项,如指定安装目录等。
编译代码:执行以下命令进行编译:
make
安装库文件:执行以下命令进行安装:
makeinsta11
默认情况下,库文件会安装到系统的默认路径中,如果需要指定安装路径,可以在配置时使用-PrefiX选项。
验证安装:可以编写一个简单的测试程序,包含IibeVent头文件并链接Iibevent库进行编译和运行,确保库文件安装正确。
注意:在编译IibeVent之前,需要确保系统已经安装了必要的依赖库,如Iibevent依赖的1ibevent-deve1>Iibevent-Openss1等。
具体依赖库的安装方法可以参考系统的文档或使用包管理工具进行安装。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
标题:深入浅出-服务器高并发库libevent (一)1安装libevent是一个开源的高并发服务器开发包,官方地址/ libevent目前有两个版本一个是1.4系列版本,一个是2.0系列版本。
我们可以在官方网站上看到类似有个stable表示稳定版本。
libevent-1.4.15-stable.tar.gz对于初学者学习,建议从1.4版本学起。
在安装libevent之前先判断本电脑是否已经安装了通过指令ls -al /usr/lib|grep libevent如果没有任何信息则表示没有安装,有的话如果发现libevent是1.3以下版本,则可以同过执行rpm -e libevent —nodeps 进行卸载。
如果是其他操作系统使用其他对应卸载指令即可。
对于下好的tar包,通过tar -zxvf libevent-release-1.4.15-stable.tar.gz指令解压。
然后执行./configure命令,但是有的包可能没有configure文件,却存在一个autogen.sh 脚本,运行这个脚本。
(如果运行不起来请安装autoconf包)然后./configure–prefix=/usrmakesudo make install安装完之后执行ls -al /usr/lib/|grep libevent如果发现有libevent文件库存在就代表安装完毕。
2 简单的libevent服务器我们通过连接libevent库来进行管理libevent库,所以在使用gcc或者g++编译的时候最后需要加上-levent下面是一个简单的libevent服务器。
#include <stdio.h>#include <string.h>#include <iostream>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <event.h>using namespace std;#define SERVER_ADDR "127.0.0.1"#define SERVER_PORT 8888// 事件basestruct event_base* base;// 读事件回调函数void onRead(int iCliFd, short iEvent, void *arg) {int iLen;char buf[1500];iLen = recv(iCliFd, buf, 1500, 0);if (iLen <= 0) {cout << "Client Close" << endl;// 连接结束(=0)或连接错误(<0),将事件删除并释放内存空间 struct event *pEvRead = (struct event*)arg; event_del(pEvRead);delete pEvRead;close(iCliFd);return;}buf[iLen] = 0;cout << "Client Info:" << buf << endl;struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL);buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));}// 连接请求事件回调函数void onAccept(int iSvrFd, short iEvent, void *arg){int iCliFd;struct sockaddr_in sCliAddr;socklen_t iSinSize = sizeof(sCliAddr);iCliFd = accept(iSvrFd, (struct sockaddr*)&sCliAddr,&iSinSize);// 连接注册为新事件 (EV_PERSIST为事件触发后不默认删除)struct event *pEvRead = new event;event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead);event_base_set(base, pEvRead);event_add(pEvRead, NULL);struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL); buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));cout<<"a client connect:"<<iCliFd<<endl;}int main(){int iSvrFd;struct sockaddr_in sSvrAddr;memset(&sSvrAddr, 0, sizeof(sSvrAddr));sSvrAddr.sin_family = AF_INET;sSvrAddr.sin_addr.s_addr = inet_addr(SERVER_ADDR); sSvrAddr.sin_port = htons(SERVER_PORT);// 创建tcpSocket(iSvrFd),监听本机8888端口iSvrFd = socket(AF_INET, SOCK_STREAM, 0);bind(iSvrFd, (struct sockaddr*)&sSvrAddr,sizeof(sSvrAddr));listen(iSvrFd, 10);// 初始化basebase = (struct event_base*)event_init();struct event evListen;// 设置事件event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL);// 设置为base事件event_base_set(base, &evListen);// 添加事件event_add(&evListen, NULL);// 事件循环event_base_dispatch(base);return 0;}通过编译指令g++ server.cpp -o server -Wall -g -I ./ -levent得到可执行程序./server启动。
如果能够编译成功并且能够正常启动,说明你操作系统的libevent安装时没问题的。
然后可以通过命令nc 127.0.0.1 8888来进行测试。
或者编写如下客户端代码:/******* 客户端程序 client.c ************/#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <netdb.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/types.h>#include <arpa/inet.h>#include<sys/time.h>#include<event.h>#define SERVER_ADDR "127.0.0.1"#define SERVER_PORT 8888int main(int argc, char *argv[]){int sockfd;char buffer[1024];struct sockaddr_in server_addr;struct hostent *host;int portnumber,nbytes;if((host=gethostbyname(SERVER_ADDR))==NULL) {fprintf(stderr,"Gethostname error\n"); exit(1);}if((portnumber=SERVER_PORT)<0){fprintf(stderr,"Usage:%s hostnameportnumber\a\n",argv[0]);exit(1);}/* 客户程序开始建立 sockfd描述符 */if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){fprintf(stderr,"SocketError:%s\a\n",strerror(errno));exit(1);}/* 客户程序填充服务端的资料 */bzero(&server_addr,sizeof(server_addr));server_addr.sin_family=AF_INET;server_addr.sin_port=htons(portnumber);server_addr.sin_addr=*((struct in_addr *)host->h_addr);/* 客户程序发起连接请求 */if(connect(sockfd,(struct sockaddr*)(&server_addr),sizeof(struct sockaddr))==-1){fprintf(stderr,"ConnectError:%s\a\n",strerror(errno));exit(1);}while(true){char MESSAGE[]="hello server..\n";//bufferevent_write(buf_ev,MESSAGE,strlen(MESSAGE));//if(-1 == (::send(sockfd,MESSAGE,strlen(MESSAGE),0))) {printf("the net has a error occured..");break;}if((nbytes = read(sockfd,buffer,1024))==-1){fprintf(stderr,"readerror:%s\n",strerror(errno));exit(1);}buffer[nbytes]='\0';printf("I have received:%s\n",buffer);memset(buffer,0,1024);sleep(2);}/* 结束通讯 */close(sockfd);exit(0);}通过编译指令g++ client.cpp -o client -Wall -g -I ./ -levent生成客户端程序client 进行测试。