这一节是安装篇。

  Socket网络编程不知不觉已经学了快两个月了。现在是时候找个网络库学学了。搜索了很多关于如何学网络编程的博客和问答。大致都是推荐学一个网络库,至于C++网络库有那么几个,各有各的好处。这里就选这个代码量少了,方便入门,等有一定的基础后,再看看“学之者生,用之着死”的ace或者有可能成为C++标准网络库的boost::asio,这个都是后话了。

  CentOS上安装软件最简单的当然是yum安装,我们可爱的libev好像现在还没有,那我们只能通过源码安装了。地址: http://dist.schmorp.de/libev/libev-4.15.tar.gz

 wget http://dist.schmorp.de/libev/libev-4.15.tar.gz
tar -zxf libev-4.15.tar.gz
cd libev-4.15
./configure
make
make install

  下面这些是安装信息

 Libraries have been installed in:
/usr/local/lib If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,-rpath -Wl,LIBDIR' linker flag
- have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for
more information, such as the ld() and ld.so() manual pages.
----------------------------------------------------------------------
/bin/mkdir -p '/usr/local/include'
/usr/bin/install -c -m ev.h ev++.h event.h '/usr/local/include'
/bin/mkdir -p '/usr/local/share/man/man3'
/usr/bin/install -c -m ev. '/usr/local/share/man/man3'

  下面给出一个官方的例子

#include <stdio.h>
#include <ev.h> //ev库头文件 //定义一个ev_TYPE 的结构体
ev_io stdin_watcher;//定义一个stdin的观测者
ev_timer timeout_watcher; //所有的watcher的回调函数都有相似的特点
//当stdin有可读的数据时,将会调用下面这个回调函数
static void stdin_cb(EV_P_ ev_io *w,int revents)
{
puts("stdin ready"); //每一次时间都必须用对应的停止函数,手动的停止其watcher
ev_io_stop(EV_A_ w);
//这将导致所有嵌套执行的ev_run停止监听
ev_break(EV_A_ EVBREAK_ALL);
} //这是一个回调函数,用于定时器回调
static void timeout_cb(EV_P_ ev_timer *w,int revents)
{
puts("timeout");
//这将导致最早运行的ev_run停止监听
ev_break(EV_A_ EVBREAK_ONE);
} int main(int argc,char **args)
{
//使用一般默认的事件循环
struct ev_loop *loop = EV_DEFAULT; //初始化一个I/O watcher,然后启动它
ev_io_init(&stdin_watcher,stdin_cb,,EV_READ);
ev_io_start(loop,&stdin_watcher); //初始化一个定时器watcher,然后启动它,只有一次,没有重复的5.5秒定时
ev_timer_init(&timeout_watcher,timeout_cb,5.5,);
ev_timer_start(loop,&timeout_watcher); //这里等待时间出发
ev_run(loop,); //撤销监听退出程序
return ;
}

  编译 gcc server.c -lev -o server 就这样是可以编译通过的,但是执行就说找不到一个libev的库。看了一下上面的安装信息,才知道要设置一下环境变量。然后才可以运行。(/etc/profile或~/.bashrc)

 export LIBDIR=/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/lib
export LD_RUN_PATH=/usr/local/lib

  用gcc -E选项编译后的源代码

 ev_io stdin_watcher;
ev_timer timeout_watcher; static void stdin_cb(struct ev_loop *loop, ev_io *w,int revents)
{
puts("stdin ready"); ev_io_stop(loop, w); ev_break(loop, EVBREAK_ALL);
} static void timeout_cb(struct ev_loop *loop, ev_timer *w,int revents)
{
puts("timeout"); ev_break(loop, EVBREAK_ONE);
} int main(int argc,char **args)
{ struct ev_loop *loop = ev_default_loop (); do { do { ((ev_watcher *)(void *)((&stdin_watcher)))->active = ((ev_watcher *)(void *)((&stdin_watcher)))->pending = ; ( (ev_watcher *)(void *)(((&stdin_watcher))))->priority = (); (((&stdin_watcher)))->cb = ((stdin_cb)); } while (); do { ((&stdin_watcher))->fd = (()); ((&stdin_watcher))->events = ((EV_READ)) | EV__IOFDSET; } while (); } while ();
ev_io_start(loop,&stdin_watcher); do { do { ((ev_watcher *)(void *)((&timeout_watcher)))->active = ((ev_watcher *)(void *)((&timeout_watcher)))->pending = ; ( (ev_watcher *)(void *)(((&timeout_watcher))))->priority = (); (((&timeout_watcher)))->cb = ((timeout_cb)); } while (); do { ((ev_watcher_time *)((&timeout_watcher)))->at = ((5.5)); ((&timeout_watcher))->repeat = (()); } while (); } while ();
ev_timer_start(loop,&timeout_watcher); ev_run(loop,); return ;
}
     do {
do {
((ev_watcher *)(void *)((&stdin_watcher)))->active = ((ev_watcher *)(void *)((&stdin_watcher)))->pending = ;
( (ev_watcher *)(void *)(((&stdin_watcher))))->priority = ();
(((&stdin_watcher)))->cb = ((stdin_cb));
} while ();
do {
((&stdin_watcher))->fd = (());
((&stdin_watcher))->events = ((EV_READ)) | EV__IOFDSET;
} while ();
} while ();
ev_io_start(loop,&stdin_watcher);

  Libev通过一个struct ev_loop结构表示一个事件驱动的框架。在这个框架里面通过ev_xxx结构,ev_init、ev_xxx_set、ev_xxx_start接口箱这个事件驱动的框架里面注册事件监控器,当相应的事件监控器的事件出现时,便会触发该事件监控器的处理逻辑,去处理该事件。处理完之后,这些监控器进入到下一轮的监控中。符合一个标准的事件驱动状态的模型。

  Libev 除了提供了基本的三大类事件(IO事件、定时器事件、信号事件)外还提供了周期事件、子进程事件、文件状态改变事件等多个事件,这里我们用三大基本事件写一个例子。

 #include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/unistd.h>
#include <ev.h> void io_action(struct ev_loop *main_loop,ev_io *io_w,int e)
{
int rst;
char buf[];
memset(buf,,sizeof(buf));
puts("In IO action");
read(STDIN_FILENO,buf,sizeof(buf));
buf[]='\0';
printf("String: %s\n",buf);
ev_io_stop(main_loop,io_w);
} void timer_action(struct ev_loop *main_loop,ev_timer *time_w,int e)
{
puts("In Time action");
ev_timer_stop(main_loop,time_w);
} void signal_action(struct ev_loop *main_loop,ev_signal *signal_w,int e)
{
puts("In Signal action");
ev_signal_stop(main_loop,signal_w);
ev_break(main_loop,EVBREAK_ALL);
} int main(int argc,char **argv)
{
ev_io io_w;
ev_timer timer_w;
ev_signal signal_w;
struct ev_loop *main_loop = ev_default_loop(); ev_init(&io_w,io_action);
ev_io_set(&io_w,STDIN_FILENO,EV_READ); ev_init(&timer_w,timer_action);
ev_timer_set(&timer_w,,); ev_init(&signal_w,signal_action);
ev_signal_set(&signal_w,SIGINT); ev_io_start(main_loop,&io_w);
ev_timer_start(main_loop,&timer_w);
ev_signal_start(main_loop,&signal_w); ev_run(main_loop,);
return ;
}

  该程序一直处于监听状态,直到有调用信号然后回调signal_w函数,该函数会调用ev_break函数退出ev_run的调用,如果注释掉第30行的代码,那么程序会在调用三个回调函数后才会结束(外包引用计数为0),否则一直监听着。具体ev_run和ev_break的参数说明如下:

void ev_run (EV_P_ int flags);

void ev_break (EV_P_ int how);

同样我们这里比较关注flags和how这两个参数。flags有下面这几个:

0:默认值。一直循环进行处理,直到外部引用计数==0或者是显示退出。
EVRUN_NOWAIT:运行一次,poll时候不会等待。如果有pending事件进行处理,否则立即返回。
EVRUN_ONCE:运行一次,poll时候会等待至少一个event发生,处理完成之后返回。
而how有下面这几个:

EVBREAK_ONE:只是退出一次ev_run这个调用。通常来说使用这个就可以了。
EVBREAK_ALL:退出所有的ev_run调用。这种情况存在于ev_run在pengding处理时候会递归调用。

  第38行创建一个struct ev_loop *结构体,上面我们给出 ev_default_loop(0) 进行创建。使用libev的核心是事件循环,可以用 ev_default_loop 或 ev_loop_new 函数创建循环,或者直接使用 EV_DEFAULT 宏,区别是 ev_default_loop 创建的事件循环不是线程安全的,而 ev_loop_new 创建的事件循环不能捕捉信号和子进程的观察器。大多数情况下,可以像下面这样使用:

if (!ev_default_loop ())
fatal ("could not initialise libev, bad $LIBEV_FLAGS in environment?");
//或者明确选择一个后端:
struct ev_loop *epoller = ev_loop_new (EVBACKEND_EPOLL | EVFLAG_NOENV);
if (!epoller)
fatal ("no epoll found here, maybe it hides under your chair");
//如果需要动态分配循环的话,建议使用 ev_loop_new 和 ev_loop_destroy 。

  在创建子进程后,且想要使用事件循环时,需要先在子进程中调用 ev_default_fork 或 ev_loop_fork 来重新初始化后端的内核状态,它们分别对应 ev_default_loop 和 ev_loop_new 来使用。

  ev_run 启动事件循环。它的第二个参数为0时,将持续运行并处理循环直到没有活动的事件观察器或者调用了 ev_break 。另外两个取值是 EVRUN_NOWAIT 和 EVRUN_ONCE 。

  ev_break 跳出事件循环(在全部已发生的事件处理完之后)。第二个参数为 EVBREAK_ONE 或 EVBREAK_ALL 来指定跳出最内层的 ev_run 或者全部嵌套的 ev_run 。

  ev_suspend 和 ev_resume 用来暂停和重启事件循环,比如在程序挂起的时候。

  接下来创建观察器,它主要包括类型、触发条件和回调函数。将它注册到事件循环上,在满足注册的条件时,会触发观察器,调用它的回调函数。上面的例子中已经包含了IO观察器和计时观察器、信号观察器,此外还有周期观察器、文件状态观察器等等。初始化和设置观察器使用 ev_init 和 ev_TYPE_set ,也可以直接使用 ev_TYPE_init 。在特定事件循环上启动观察器使用 ev_TYPE_start 。 ev_TYPE_stop 停止观察器,并且会释放内存。libev中将观察器分为4种状态:初始化、启动/活动、等待、停止。libev中的观察器还支持优先级。

  下面将介绍各个观察器(watcher)

  ev_io  获取标准输入

 static void stdin_readable_cb (struct ev_loop *loop, ev_io *w, int revents)
{
ev_io_stop (loop, w);
//.. read from stdin here (or from w->fd) and handle any I/O errors
} ev_io stdin_readable;
ev_io_init (&stdin_readable, stdin_readable_cb, STDIN_FILENO, EV_READ);
ev_io_start (loop, &stdin_readable);

  ev_timer  创建一个 ?? 秒之后启动的计时器

 static void one_minute_cb (struct ev_loop *loop, ev_timer *w, int revents)
{
//创建一个60秒的计时器
//.. one minute over, w is actually stopped right here
} ev_timer mytimer;
ev_timer_init (&mytimer, one_minute_cb, ., .);
ev_timer_start (loop, &mytimer);

  创建一个10s超时的超时器

 static void timeout_cb (struct ev_loop *loop, ev_timer *w, int revents)
{
//.. ten seconds without any activity
} ev_timer mytimer;
ev_timer_init (&mytimer, timeout_cb, ., .); /* note, only repeat used */
ev_timer_again (&mytimer); /* start timer */
ev_run (loop, ); // and in some piece of code that gets executed on any "activity":
// reset the timeout to start ticking again at 10 seconds
ev_timer_again (&mytimer);

  ev_periodic 创建一个小时为单位的周期定时器

 static void clock_cb (struct ev_loop *loop, ev_periodic *w, int revents)
{
// ... its now a full hour (UTC, or TAI or whatever your clock follows)
} ev_periodic hourly_tick;
ev_periodic_init (&hourly_tick, clock_cb, ., ., );
ev_periodic_start (loop, &hourly_tick);

  自定义周期计算方式

 #include <math.h>

 static ev_tstamp my_scheduler_cb (ev_periodic *w, ev_tstamp now)
{
return now + (. - fmod (now, .));
} ev_periodic_init (&hourly_tick, clock_cb, ., ., my_scheduler_cb);

  如果想从当前时间开始

 ev_periodic hourly_tick;
ev_periodic_init (&hourly_tick, clock_cb, fmod (ev_now (loop), .), ., );
ev_periodic_start (loop, &hourly_tick);

  ev_signal 在收到 SIGINT 时做些清理

 static void sigint_cb (struct ev_loop *loop, ev_signal *w, int revents)
{
ev_break (loop, EVBREAK_ALL);
} ev_signal signal_watcher;
ev_signal_init (&signal_watcher, sigint_cb, SIGINT);
ev_signal_start (loop, &signal_watcher);

  ev_child   fork 一个新进程,给它安装一个child处理器等待进程结束

 ev_child cw;

 static void
child_cb (EV_P_ ev_child *w, int revents)
{
ev_child_stop (EV_A_ w);
printf ("process %d exited with status %x\n", w->rpid, w->rstatus);
} pid_t pid = fork (); if (pid < )
// error
else if (pid == )
{
// the forked child executes here
exit ();
}
else
{
ev_child_init (&cw, child_cb, pid, );
ev_child_start (EV_DEFAULT_ &cw);
}

  ev_stat 文件状态观察器

  监控/etc/passwd是否有变化

 static void passwd_cb (struct ev_loop *loop, ev_stat *w, int revents)
{
/* /etc/passwd changed in some way */
if (w->attr.st_nlink)
{
printf ("passwd current size %ld\n", (long)w->attr.st_size);
printf ("passwd current atime %ld\n", (long)w->attr.st_mtime);
printf ("passwd current mtime %ld\n", (long)w->attr.st_mtime);
}
else
/* you shalt not abuse printf for puts */
puts ("wow, /etc/passwd is not there, expect problems. if this is windows, they already arrived\n");
} ...
ev_stat passwd; ev_stat_init (&passwd, passwd_cb, "/etc/passwd", .);
ev_stat_start (loop, &passwd);

  下一小节就对那几个常用的事件驱动类型进行简单例子编写。

  参考资料: http://wenku.baidu.com/view/957ea001b52acfc789ebc9bf.html

      : Libev手册 http://cvs.schmorp.de/libev/ev.pod

      : http://my.oschina.net/u/917596/blog/176658

      : http://dirlt.com/libev.html

      : http://www.yeolar.com/note/2012/12/16/libev/

  本文地址: http://www.cnblogs.com/wunaozai/p/3950249.html

Socket网络编程--Libev库学习(1)的更多相关文章

  1. Socket网络编程--Libev库学习(3)

    这一小节继续讲解各个观察器(Watcher). 上一小节已经讲解了ev_io(IO可读可写观察器),ev_stat(文件属性变化观察器),ev_signal(信号处理观察器),ev_timer(定时器 ...

  2. Socket网络编程--Libev库学习(2)

    这一小节讲各个观察器(Watcher) 在libev下面watcher相当于EventHandler这么一个概念,通常里面会绑定fd回调函数以及我们需要关注的事件. 然后一旦触发事件之后会触发我们使用 ...

  3. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  4. windows socket 网络编程

    样例代码就在我的博客中,包含六个UDP和TCP发送接受的cpp文件,一个基于MFC的局域网聊天小工具project,和此小工具的全部执行时库.资源和执行程序.代码的压缩包位置是http://www.b ...

  5. Linux Socket 网络编程

    Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后 ...

  6. Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ ...

  7. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  8. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  9. Socket网络编程--FTP客户端

    Socket网络编程--FTP客户端(1)(Windows) 已经好久没有写过博客进行分享了.具体原因,在以后说. 这几天在了解FTP协议,准备任务是写一个FTP客户端程序.直接上干货了. 0.了解F ...

随机推荐

  1. FreeRTOS队列

    简单来讲队列是任务间通信的方式,队列本身是可以存储消息的,队列的消息可以由一个或者多个任务写入,也可以由一个或者多个任务读出,总之消息队列是任务间通信方式:

  2. C语言的基本数据类型

     代码如下: // text.cpp: 定义控制台应用程序的入口点. // #include "stdafx.h" int main() { int a; //告诉编译器,分配 4 ...

  3. CF888G Xor-MST 生成树、分治、Trie树合并

    传送门 第一次接触到Boruvka求最小生成树 它的原版本是:初始每一个点构成一个连通块,每一次找到每一个连通块到其他的连通块权值最短的边,然后合并这两个连通块.因为每一次连通块个数至少减半,所以复杂 ...

  4. kubectl客户端工具远程连接k8s集群

    一.概述 一般情况下,在k8smaster节点上集群管理工具kubectl是连接的本地http8080端口和apiserver进行通讯的,当然也可以通过https端口进行通讯前提是要生成证书.所以说k ...

  5. CF 859E Desk Disorder

    题目大意:一个经典的游戏:抢椅子.有\(n\)个人以及\(2n\)把椅子.开始时每个人坐在一把椅子上,而且他们每个人都有一个下一步想坐的位置(可以与之前重合).每一个下一次可以在自己现在做的椅子和想坐 ...

  6. [Oracle]构筑TDE 环境的例子

    构筑TDE 环境的例子: 测试环境:12.1.0.2 $ cd $ORACLE_HOME/network/admin$ vim sqlnet.ora $ pwd/u01/app/oracle/prod ...

  7. OpenTK教程-1绘制一个三角形

    OpenTK的官方文档是真心的少,他们把怎么去安装OpenTK说的很清楚,但是也就仅限于此,这有一篇learn opentk in 15的教程(链接已经失效,译者注),但是并不完美.你可以在15分钟内 ...

  8. Android恶意样本数据集汇总

    硕士论文的研究方向为Android恶意应用分类,因此花了一点时间去搜集Android恶意样本.其中一部分来自过去论文的公开数据集,一部分来自社区或平台的样本.现做一个汇总,标明了样本或数据集的采集时间 ...

  9. C#_Math函数总结

    Math.abs() 计算绝对值. Math.acos() 计算反余弦值. Math.asin() 计算反正弦值. Math.atan() 计算反正切值. Math.atan2() 计算从x 坐标轴到 ...

  10. Oracle数据库冷备份与热备份操作梳理

    Oracle数据库的备份方式有冷备份和热备份两种,针对这两种备份的实施过程记录如下: 一.Oracle冷备份 概念数据库在关闭状态下完成所有物理系统文件拷贝的过程,也称脱机备份.适合于非归档模式(即n ...