这一小节继续讲解各个观察器(Watcher).

  上一小节已经讲解了ev_io(IO可读可写观察器),ev_stat(文件属性变化观察器),ev_signal(信号处理观察器),ev_timer(定时器),ev_periodic(周期任务处理),ev_child(子进程状态变化观察器)。这一小节准备讲ev_fork(创建的进程时的观察器),ev_async(异步调用观察器),ev_cleanup(event loop退出时触发事件),ev_prepare(每次event loop之前事件),ev_check(每次event loop之后事件),ev_idle(每次event loop空闲触发事件).

  ev_async  (ev_async当ev_async_send通过watcher调用时调用,触发EV_ASYNC)

1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <ev.h>
6
7 ev_async async_watcher;8
9 static void sigint_callback(struct ev_loop *loop,ev_signal * w,intrevents)10 {11     if(revents &EV_SIGNAL)12 {13         printf("Call sigint_callback\n");14         printf("ev_async_send 调用前 %d\n",ev_async_pending(&async_watcher));15         ev_async_send(loop,&async_watcher);//这里会调用async_callback
16         printf("ev_async_send 调用后 %d\n",ev_async_pending(&async_watcher));17 }18 }19
20 static void sigquit_callback(struct ev_loop *loop,ev_signal *w,intrevetns)21 {22     printf("Call sigquit_callback\n");23 ev_break(loop,EVBREAK_ALL);24 }25
26 static void async_callback(struct ev_loop *loop,ev_async *w,intrevents)27 {28     if(revents &EV_ASYNC)29 {30         printf("Call async_callback\n");31 }32 }33
34 int main(int argc, char **args)35 {36     struct ev_loop *main_loop=ev_default_loop(0);37
38     ev_init(&async_watcher,async_callback);39     ev_async_start(main_loop,&async_watcher);40
41 ev_signal sigint_watcher;42     ev_init(&sigint_watcher,sigint_callback);43     ev_signal_set(&sigint_watcher,SIGINT);44     ev_signal_start(main_loop,&sigint_watcher);45
46     ev_signal sigquit_watcher;//这里的ev_signal不能与上面共用,必须在声明一个变量
47     ev_init(&sigquit_watcher,sigquit_callback);48     ev_signal_set(&sigquit_watcher,SIGQUIT);49     ev_signal_start(main_loop,&sigquit_watcher);50
51     ev_run(main_loop,0);52     return 0;53 }

  下面这个是运行截图

  可以看出程序ev_async这个是通过ev_async_send来驱动async_callback这个回调函数执行的。而且ev_async_pending这个也是可以判断ev_async是否处于pending状态。我在第15行处增加了sleep(1)后,运行的结构还是一样,可以看出ev_async所绑定的回调函数是处于pending状态而不是另外开一个线程(进程)来执行的。

  从上面的处理机制看,好像就是发送一个信号,然后ev_async就调用回调函数去执行,好像跟ev_signal一样,没有什么特点啊。这里给出官方文档的解释。

This functionality is very similar to ev_signal watchers, as signals, too, are asynchronous innature, and signals, too, will be compressed (i.e. the number of callback invocations may be less than the number of ev_async_sent calls).Unlike ev_signal watchers, ev_async works with anyevent loop, not just the default loop.

  上面说到,不同与ev_signal watchers的是,ev_async可以在多种event loop,而不是默认的loop。前几小节已经讲到ev_loop 的创建,可以通过ev_loop_new进行创建(创建异步事件什么的)。具体的用法这里还不是很清楚,先跳过。

  ev_fork (开辟进程时观察器)

1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <ev.h>
6
7 static void fork_callback(struct ev_loop *loop,ev_fork *w,intrevents)8 {9     printf("Call fork_callback\n");10 }11
12 static void timeout_callback(struct ev_loop*loop,ev_timer *w,intrevents)13 {14     printf("Time Out\n");15 ev_break(loop,EVBREAK_ALL);16 }17
18 int main(int argc, char **args)19 {20     struct ev_loop *main_loop=ev_default_loop(0);21
22 ev_fork fork_watcher;23     ev_init(&fork_watcher,fork_callback);24     ev_fork_start(main_loop,&fork_watcher);25
26 ev_timer timer_watcher;27     ev_init(&timer_watcher,timeout_callback);28     ev_timer_set(&timer_watcher,3,0);29     ev_timer_start(main_loop,&timer_watcher);30
31     switch(fork())32 {33         case -1:34             break;35         case 0://child36             //ev_loop_fork(main_loop);
37             break;38 }39
40     ev_run(main_loop,0);41     return 0;42 }

  上面这个代码没有输出Call fork_callback,如果把第36行的注释去掉,就会输出Call fork_callback了,可以说明这个ev_fork不是针对fork函数创建的进程。而是要ev_loop_fork针对ev_loop 创建的loop。具体解释的不是很清楚,下面给出官方文档:

Fork watchers are called when a fork () was detected (usually because whoever is a good citizen cared to tell libev about it by calling ev_default_fork or ev_loop_fork). The invocation is done before the event loop blocks next and before ev_check watchers are being called, and only in the child after the fork. If whoever good citizen calling ev_default_fork cheats and calls it in the wrong process, the fork handlers will be invoked, too, of course.

  loop的创建小解

1 struct ev_loop *ev_default_loop (unsigned int flags) 2 struct ev_loop *ev_loop_new (unsigned int flags) 3 //这两个函数都是默认原始化一个loop,区别是第一个不是线程安全的,第二个不能捕捉信号和子进程的watcher。4 //参数flags可以为下面几种类型:5 //引用
6 #define EVFLAG_AUTO        0x00000000U /* not quite a mask */
7 /*flag bits*/
8 #define EVFLAG_NOENV       0x01000000U /* do NOT consult environment */
9 #define EVFLAG_FORKCHECK   0x02000000U /* check for a fork in each iteration */
10 /*method bits to be ored together*/
11 #define EVBACKEND_SELECT   0x00000001U /* about anywhere */
12 #define EVBACKEND_POLL     0x00000002U /* !win */
13 #define EVBACKEND_EPOLL    0x00000004U /* linux */
14 #define EVBACKEND_KQUEUE   0x00000008U /* bsd */
15 #define EVBACKEND_DEVPOLL  0x00000010U /* solaris 8 */ /* NYI */
16 #define EVBACKEND_PORT     0x00000020U /* solaris 10 */
17 ev_default_fork () 18 ev_loop_fork (loop)19 //这两个函数就是当你在子进程里须要 运用 libev的函数的之前必须要调用。他们的区别是第二个函数是当运用 ev_loop_new建立 的loop时,才用第二个函数,也就是说重用父进程建立 的loop。
20 ev_loop (loop, int flags)21 //开始事件循环。
22 ev_TYPE_init (ev_TYPE *watcher, callback, [args])23 //原始化一个watcher。TYPE也就是libev支持的事件类型,比如io,比如time等等。。24 //第一个参数为一个watcher,第二个回调函数,第三个句柄,第四个事件类型。包含下面几种:25 //引用
26 #define EV_UNDEF     -1 /* guaranteed to be invalid */
27 #define EV_NONE      0x00 /* no events */
28 #define EV_READ      0x01 /* ev_io detected read will not block */
29 #define EV_WRITE     0x02 /* ev_io detected write will not block */
30 #define EV_IOFDSET   0x80 /* internal use only */
31 #define EV_TIMEOUT   0x00000100 /* timer timed out */
32 #define EV_PERIODIC  0x00000200 /* periodic timer timed out */
33 #define EV_SIGNAL    0x00000400 /* signal was received */
34 #define EV_CHILD     0x00000800 /* child/pid had status change */
35 #define EV_STAT      0x00001000 /* stat data changed */
36 #define EV_IDLE      0x00002000 /* event loop is idling */
37 #define EV_PREPARE   0x00004000 /* event loop about to poll */
38 #define EV_CHECK     0x00008000 /* event loop finished poll */
39 #define EV_EMBED     0x00010000 /* embedded event loop needs sweep */
40 #define EV_FORK      0x00020000 /* event loop resumed in child */
41 #define EV_ASYNC     0x00040000 /* async intra-loop signal */
42 #define EV_ERROR     0x80000000 /* sent when an error occurs */
43 //引用
44 ev_TYPE_start (loop *, ev_TYPE *watcher)45 //启动一个watcher。

1     switch(fork())2 {3         case -1:4             break;5         case 0://child
6             ev_loop_fork(main_loop);//使用父进程main_loop
7 ev_timer timer_watcher1;8             ev_init(&timer_watcher1,timeout_callback);9             ev_timer_set(&timer_watcher1,3,0);10             ev_timer_start(main_loop,&timer_watcher1);11             break;12     }

  上面代码如果修改如下是可以编译通过的。就是在父进程中的main_loop中再增加一个watcher,这个程序将会输出三次Time Out。注意如果没有第六行的ev_loop_fork是编译不通过的。大概的原因是ev库设计的原因。

  下面给出一个例子,用于以后可以参考用

1 #include <ev.h>
2 #include <stdio.h>
3
4 //不同的watcher
5 ev_io stdin_watcher;6 ev_timer timeout_watcher;7 ev_timer timeout_watcher_child;8
9 //标准输入的回调函数
10 static void stdin_cb (EV_P_ ev_io *w, intrevents)11 {12     puts ("stdin ready");13 ev_io_stop (EV_A_ w);14 ev_unloop (EV_A_ EVUNLOOP_ALL);15 }16
17 //父进程的定时器回调函数
18 static void timeout_cb (EV_P_ ev_timer *w, intrevents)19 {20     puts ("timeout");21 ev_unloop (EV_A_ EVUNLOOP_ONE);22 }23 //子进程的定时器回调函数
24 static void timeout_cb_child (EV_P_ ev_timer *w, intrevents)25 {26     puts ("child timeout");27 ev_unloop (EV_A_ EVUNLOOP_ONE);28 }29
30 static void fork_callback(struct ev_loop *loop,ev_fork *w,intrevents)31 {32     printf("Call fork_callback\n");33 }34
35 int main (void)36 {37     //创建一个backend为select的loop
38     struct ev_loop *loop =ev_loop_new(EVBACKEND_SELECT);39
40     //初始化并启动父进程的watcher
41     ev_timer_init(&timeout_watcher, timeout_cb, 10, 0.);42     ev_timer_start(loop, &timeout_watcher);43     switch(fork()) {44         case -1:45             return -1;46         case 0:47             //使用父进程loop。
48 ev_loop_fork(loop);49             //子进程的loop
50             struct ev_loop *loop_child =ev_loop_new (EVBACKEND_SELECT);51             ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ 0, EV_READ);52             ev_io_start (loop, &stdin_watcher);53             ev_timer_init(&timeout_watcher_child, timeout_cb_child, 5.5, 0.);54             ev_timer_start(loop_child, &timeout_watcher_child);55             ev_loop(loop_child,0);56 }57
58     //等待事件
59     ev_loop (loop, 0);60     return 0;61 }

  ev_cleanup  event loop 退出触发事件

1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <ev.h>
6
7 struct ev_loop *main_loop;8
9 static void program_exits(void)10 {11     printf("Call AtExit\n");12     ev_loop_destroy(EV_DEFAULT);//注释掉43行处代码,该函数在这里没有调用到cleanup_callback,但是却执行没有错误
13 }14
15 static void cleanup_callback(struct ev_loop *loop,ev_cleanup *w,intrevents)16 {17     printf("Call cleanup_callback\n");18 }19
20 static void timer_callback(struct ev_loop *loop,ev_timer *w,intrevents)21 {22     printf("Call timer_callback\n");23 }24
25 int main(int argc, char **args)26 {27     //struct ev_loop *main_loop=ev_default_loop(0);//error 注意ev_loop_destroy与ev_loop_new对应
28     main_loop=ev_loop_new(EVBACKEND_EPOLL);29
30 ev_cleanup cleanup_watcher;31     ev_init(&cleanup_watcher,cleanup_callback);32     ev_cleanup_start(main_loop,&cleanup_watcher);33
34 ev_timer timer_watcher;35     ev_init(&timer_watcher,timer_callback);36     ev_timer_set(&timer_watcher,0.2,0);37     ev_timer_start(main_loop,&timer_watcher);38
39 atexit(program_exits);40
41     ev_run(main_loop,0);42
43     ev_loop_destroy(main_loop);//在这里就可以调用到cleanup_callback
44     printf("END\n");45     return 0;46 }

  运行时截图

  ev_prepare  (每次event loop之前事件)

  ev_check  (每次event loop之后事件)

1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <ev.h>
6
7 static void prepare_callback(struct ev_loop *loop,ev_prepare *w,intrevents)8 {9     printf("Prepare Callback\n");10 }11
12 static void check_callback(struct ev_loop *loop,ev_check *w,intrevents)13 {14     printf("Check Callback\n");15 }16
17 static void timer_callback(struct ev_loop *loop,ev_timer *w,intrevents)18 {19     printf("Timer Callback\n");20 }21
22 static void sigint_callback(struct ev_loop *loop,ev_signal *w,intrevents)23 {24     printf("Sigint Callback\n");25 ev_break(loop,EVBREAK_ALL);26 }27
28 int main(int argc, char **args)29 {30     struct ev_loop *main_loop=ev_default_loop(0);31
32 ev_prepare prepare_watcher;33 ev_check check_watcher;34 ev_timer timer_watcher;35 ev_signal signal_watcher;36
37     ev_prepare_init(&prepare_watcher,prepare_callback);38     ev_check_init(&check_watcher,check_callback);39     ev_timer_init(&timer_watcher,timer_callback,2,0);40     ev_signal_init(&signal_watcher,sigint_callback,SIGINT);41
42     ev_prepare_start(main_loop,&prepare_watcher);43     ev_check_start(main_loop,&check_watcher);44     ev_timer_start(main_loop,&timer_watcher);45     ev_signal_start(main_loop,&signal_watcher);46
47     ev_run(main_loop,0);48     return 0;49 }

  运行结果

  看前三个为一组,我测试了几次都是这样,Timer Callback的输出都是在Check之后,这个不知道为什么不过后面的捕获SIGINT信号就没有这个问题,SIGINT信号的回调函数的输出是处于Prepare和Check之间。这个就符合预想。还有就是我们输入一个Ctrl-C时,也会触发Prepare-Check的回调函数。这个倒是没有想到,应该是一个ev_signal会向ev_loop里放入两个处理过程,一个是Linux默认的捕获SIGINT信号(signal函数)一个是我们的回调函数,大概是在默认的回调函数中调用我们的回调函数,毕竟捕获信号是系统调用。上面这个是我的猜想(理解),不一定是正确的。

  ev_idle (每次event loop空闲触发事件)

1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <ev.h>
6
7 ev_idle idle_watcher;8 int count=0;9
10 static void timer_callback_start(struct ev_loop *loop,ev_timer *w,intrevents)11 {12     printf("Timer Callback Start\n");13     ev_idle_start(loop,&idle_watcher);14 }15 static void timer_callback_stop(struct ev_loop *loop,ev_timer *w,intrevents)16 {17     printf("Timer Callback Stop\n");18     ev_idle_stop(loop,&idle_watcher);19 }20
21 static void sigint_callback(struct ev_loop *loop,ev_signal *w,intrevents)22 {23     printf("Sigint Callback\n");24 ev_break(loop,EVBREAK_ALL);25 }26
27 static void idle_callback(struct ev_loop *loop,ev_idle *w,intrevents)28 {29     count++;30 }31
32 int main(int argc, char **args)33 {34     struct ev_loop *main_loop=ev_default_loop(0);35
36 ev_timer timer_watcher_start;37 ev_timer timer_watcher_stop;38 ev_signal signal_watcher;39
40     ev_idle_init(&idle_watcher,idle_callback);41     ev_timer_init(&timer_watcher_start,timer_callback_start,1,0);42     ev_timer_init(&timer_watcher_stop,timer_callback_stop,3,0);43     ev_signal_init(&signal_watcher,sigint_callback,SIGINT);44
45     ev_timer_start(main_loop,&timer_watcher_start);46     ev_timer_start(main_loop,&timer_watcher_stop);47     ev_signal_start(main_loop,&signal_watcher);48
49     ev_run(main_loop,0);50
51     printf("从第1秒到第3秒之间count计数器的累加到 %d\n",count);52     return 0;53 }

  运行结果

  我们的idle是可以控制开始和结束的。而这个idle的作用是但event_loop处于空闲的时候,与其在ev_run阻塞等待,不如利用这时的cpu时间来做其他事。应用的话,就是如果服务器繁忙的话就主要处理请求等,如果服务器请求不多时,可以利用cpu时间来处理备份什么的,这样就可以最大限度的利用cpu了。

  观察器watcher差不多就这些了,还有个ev_embed这个还不会用。

  参考资料: http://wangjunle23.blog.163.com/blog/static/11783817120124308920321/

        : http://simohayha.iteye.com/blog/306712

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

转载于:https://www.cnblogs.com/wunaozai/p/3955156.html

Socket网络编程--Libev库学习(3)相关推荐

  1. 使用Dev C++进行Windows socket网络编程,需链接lws2_32库

    背景 在我们使用Dev C++进行C语言编程时,如果我们引入的库是C语言标准库,那我们是不要在编译器选项中进行额外的设置的,但是如果我们使用的是一些不是C语言标准库,那我们可能就需要在编译器选择中进行 ...

  2. Linux C++/Java/Web/OC Socket网络编程

    一,Linux C++ Socket网络编程 1.什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制 ...

  3. 视频教程-C++socket网络编程--http服务器(支持php)实战教学视频-C/C++

    C++socket网络编程--http服务器(支持php)实战教学视频 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟仿真, ...

  4. C++socket网络编程大全实战http服务器(支持php)视频课程-夏曹俊-专题视频课程

    C++socket网络编程大全实战http服务器(支持php)视频课程-16782人已学习 课程介绍         C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本 ...

  5. python运维开发之socket网络编程01

    python运维开发之socket网络编程01说明:本文来自来自北京老男孩linux运维实战培训中心-运维开发课程免费视频内容,本文内容为系列内容,更多分享信息见:http://oldboy.blog ...

  6. Socket网络编程(2)--服务端实现

    中秋了,首先祝大家中秋快乐,闲着无事在家整一个socket的聊天程序,有点仿QQ界面,就是瞎折腾,不知道最后是不是能将所有功能实现. 如果你对socket不了解,请看这篇文章:http://www.c ...

  7. 《爬虫与网络编程基础》学习

    <爬虫与网络编程基础>学习 任务1:计算机网络基础 Step1-2 Step 3:关于XML格式的学习 XML文件格式 XML文件的常见操作 1.构建xml格式文件 2. 保存XML文件 ...

  8. 多实例多进程网络编程PHP,php socket网络编程基础知识(四):多进程

    标签:status   传递   windows   返回   修改   队列   _for   响应   关联 说明 php在web编程时是不需要考虑多进程的,但整个php流程是涉及到多进程的,只不 ...

  9. socket网络编程 java_Java Web 基础(一) 基于TCP的Socket网络编程

    一.Socket简单介绍 Socket通信作为Java网络通讯的基础内容,集中了异常.I/O流模式等众多知识点.学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解. 1 ...

最新文章

  1. 云计算技术 — 云计算的商业模式与部署模式
  2. 哈夫曼编码(Huffman)Java实现代码
  3. 工程实战-ES6环境配置
  4. Excel有用的函数(ISBLANK,IF,LEFT,VALUE)
  5. inetd的工作流程
  6. [mybatis]缓存_一级缓存_一级缓存失效的四种情况
  7. native react 变颜色 点击_在React Native中按下更改按钮样式(Change button style on press in React Native)...
  8. 苹果查询水货苹果笔记本(Mac Book)验机流程
  9. Postgres外部表示例
  10. python正则表达式re模块_详解Python正则表达式re模块
  11. PHP-redis中文帮助手册_set相关
  12. Spring boot 跨域请求实现方式汇总
  13. Java开发笔记(一百四十九)引入预报告的好处
  14. CSS+HTML 顶部导航栏实现
  15. 北京科技大学计算机组成原理,北京科技大学二十套计算机组成原理题库及答案...
  16. 吃透浏览器安全(同源限制/XSS/CSRF/中间人攻击)
  17. Prometheus -Grafana部署及部署告警
  18. 计算机信息技术对医院医疗服务工作的影响,计算机在医院信息管理工作中应用探究.doc...
  19. 插件体系结构软件开发方法研究
  20. Python键盘按键模拟

热门文章

  1. vs 警告被视为错误
  2. 计算机科学文学学士,波士顿大学计算机科学.pdf
  3. KubeEdge 1.1 部署
  4. java中 static变量和方法到底是存在内存什么区域?
  5. 【算法】平衡二叉树 Avl 树
  6. 【java】java JVM问题定位的典型案例分析 笔记 finalizer
  7. 【es】将 elasticsearch 写入速度优化到极限
  8. 【registries】registrie rest-service idea 无法引入
  9. 【ES】分布式调度系统之 Elastic-Job-Lite
  10. 【Logstash】记录一次logstash拉取数据很慢的问题