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

  这一小节继续讲解各个观察器(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,int revents)
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,int revetns)
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,int revents)
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 in nature, 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 any event 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,int revents)
 8 {
 9     printf("Call fork_callback\n");
10 }
11
12 static void timeout_callback(struct ev_loop*loop,ev_timer *w,int revents)
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://child
36             //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, int revents)
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, int revents)
19 {
20     puts ("timeout");
21     ev_unloop (EV_A_ EVUNLOOP_ONE);
22 }
23 //子进程的定时器回调函数
24 static void timeout_cb_child (EV_P_ ev_timer *w, int revents)
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,int revents)
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,int revents)
16 {
17     printf("Call cleanup_callback\n");
18 }
19
20 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
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,int revents)
 8 {
 9     printf("Prepare Callback\n");
10 }
11
12 static void check_callback(struct ev_loop *loop,ev_check *w,int revents)
13 {
14     printf("Check Callback\n");
15 }
16
17 static void timer_callback(struct ev_loop *loop,ev_timer *w,int revents)
18 {
19     printf("Timer Callback\n");
20 }
21
22 static void sigint_callback(struct ev_loop *loop,ev_signal *w,int revents)
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,int revents)
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,int revents)
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,int revents)
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,int revents)
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

时间: 2024-10-14 20:39:58

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

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

这一小节讲各个观察器(Watcher) 在libev下面watcher相当于EventHandler这么一个概念,通常里面会绑定fd回调函数以及我们需要关注的事件. 然后一旦触发事件之后会触发我们使用的回调函数,回调函数参数通常有reactor,watcher以及触发的事件.这里不打算重复文档里面的watcher 相关的内容和对应的API,但是对于某些内容的话可能会提到并且附带一些注释.之前我们还是看看通用过程,这里使用TYPE区分不同类型watcher. 1 typedef void (*)(

Linux程序设计学习笔记----Socket网络编程基础之TCP/IP协议簇

转载请注明出处: ,谢谢! 内容提要 本节主要学习网络通信基础,主要涉及的内容是: TCP/IP协议簇基础:两个模型 IPv4协议基础:IP地址分类与表示,子网掩码等 IP地址转换:点分十进制\二进制 TCP/IP协议簇基础 OSI模型 我们知道计算机网络之中,有各种各样的设备,那么如何实现这些设备的通信呢? 显然是通过标准的通讯协议,但是,整个网络连接的过程相当复杂,包括硬件.软件数据封包与应用程序的互相链接等等,如果想要写一支将联网全部功能都串连在一块的程序,那么当某个小环节出现问题时,整只

socket 网络编程快速入门(一)教你编写基于UDP/TCP的服务(客户端)通信

因为UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,因为这些函数的结构往往比较复杂,参数大部分都是结构体,令人难以记忆和理解. 但是一旦我们知道这些函数包括其参数的具体含义,socket网络编程也就变得不是那么复杂.这里不赘述 具体函数的详细含义,网络上有很多的文章,同时笔者建议大家参考 MSDN,对返回值,参数等会有更好的理解. 以下均为单线程的简单实例,多线程的请关注下一篇文章. (

windows下的socket网络编程(入门级)

windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket网路通信的例子,以便以后用到的时候有个参考. windows下使用winsock编程与linux/unix的区别在于windows下需要先有一个初始化的操作,结束的时候需要一个清理的操作.还有windows下编译的时候需要连接ws32_lib库. 大致过程如下 1.初始

Linux Socket 网络编程

Linux下的网络编程指的是socket套接字编程,入门比较简单.在学校里学过一些皮毛,平时就是自学玩,没有见识过真正的socket编程大程序,比较遗憾.总感觉每次看的时候都有收获,但是每次看完了之后,过段时间不看,重新拾起这些知识的时候又要从头开始,所以,在这里做个笔记也算是做个模板,以后可以直接从某一个阶段开始接着玩... 1. socket套接字介绍 socket机制其实就是包括socket, bind, listen, connect, accept等函数的方法,其通过指定的函数实现不同

Socket网络编程初探

MarkdownPad Document Socket网络编程初探 客户端/服务器架构 即C/S架构,其实web服务在某种意义上也算是C/S架构 一个特点是服务器端持续运行对外提供服务 为何学习socket一定要先学习互联网协议: C/S架构的软件是基于网络进行通信的 网络的核心就是一堆协议,即标准,想要开发一款基于网络通信的软件就必须遵循这些标准 socket是处在应用层和传输层中间的一组接口 说到这,那么socket到底是个什么呢?Socket是应用层与TCP/IP协议族通信的中间软件抽象层

Python全栈【Socket网络编程】

Python全栈[socket网络编程] 本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" 用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式

Python Socket 网络编程

Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页.QQ 聊天.收发 email 等等.要解决网络上两台主机之间的进程通信问题,首先要唯一标识该进程,在 TCP/IP 网络协议中,就是通过 (IP地址,协议,端口号) 三元组来标识进程的,解决了进程标识问题,就有了通信的基础了. 本文主要介绍使用 Python 进行 TCP Socket 网络编程,假设你已

socket 网络编程高速入门(一)教你编写基于UDP/TCP的服务(client)通信

由于UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,由于这些函数的结构往往比較复杂,參数大部分都是结构体,令人难以记忆和理解. 可是一旦我们知道这些函数包含其參数的详细含义,socket网络编程也就变得不是那么复杂. 这里不赘述 详细函数的详细含义.网络上有非常多的文章.同一时候笔者建议大家參考 MSDN.对返回值,參数等会有更好的理解. 下面均为单线程的简单实例,多线程的请关注下一篇文