上一篇讲到了libiop基本结构
,这次根据libiop提供的test跟踪下消息和运行流程
1 | void echo_server_test() |
echo_server_test
函数内部添加了一个tcpserver,将函数一层一层展开,展开iop_add_tcp_server
1 | int iop_add_tcp_server(iop_base_t *base, const char *host, unsigned short port, |
解读iop_add_tcp_server
,函数参数iop_base_t
是iop基本事件结构
,前面有说过,
1 | struct tag_iop_base_t |
第二个参数host是主机地址
,port是端口号
,剩下的parser为解析函数指针
,processor为处理函数指针
,on_connect为连接的回调函数指针
,`on_destroy,为
销毁功能函数指针,
on_error为错误情况下函数指针,
keepalive_timeout为超时时间`
这几个函数指针的类型如下,基本都类似的
1 | /*tcp连接事件回调函数*/ |
回到iop_add_tcp_server函数
里
开辟arg的空间
sarg = (iop_tcp_server_arg_t *)malloc(sizeof(iop_tcp_server_arg_t));
绑定端口和地址
h = iop_tcp_server(host,port);
对arg赋值
1 | sarg->port = port; |
下面这句代码最重要
iop_add(base,h,EV_TYPE_READ,_iop_tcp_server_cb,(void *)sarg,-1); 这句代码将socket h绑定了一个读事件,当有读事件就绪时会触发iop_tcp_server_cb这个函数
。
如何将h和iop_tcp_server_cb绑定的,展开iop_add
1 | int iop_add(iop_base_t *base,io_handle_t handle,unsigned int events,iop_event_cb evcb,void *arg,int timeout) |
iop_add 形参不做解释,其中形参evcb也是函数指针
/*事件回调函数,返回-1代表要删除对象,返回0代表正常*/ typedef int (*iop_event_cb)(iop_base_t *,int,unsigned int,void *);
在iop_add内部完成iop回调函数evcb的绑定和基本参数赋值,然后判断是io事件还是定时器事件,对于IO事件,要通知网络层(epoll,select等不同模型)进行绑定, 调用base中op_imp成员的base_add函数指针完成绑定。
r = (*(base->op_imp.base_add))(base, iop->id, handle, events);
之所以能调用是因为之前op_imp.base_add被赋值了。回到
1 | void echo_server_test() |
一层一层看
1 | iop_base_t* iop_base_new_special(int maxio,const char *model) |
1 | int iop_init_epoll(void *iop_base, int maxev) |
上面就是在new函数里实现的一层一层函数指针的绑定,所以之后才可以调用对应的函数指针。
在iop_add 函数绑定成功后,整个iop_add_tcp_server流程走完了。
我们下一步看看如何派发消息
1 | void echo_server_test() |
iop_run函数完成消息轮询和派发
1 | void iop_run(iop_base_t *base) |
`
iop_dispatch消息派发函数
iop_base_free iop_base释放
`
1 | int iop_dispatch(iop_base_t *base) |
这句代码是消息派发的关键
//调用不同模型的函数指针实现消息派发
dispatch_imp_cb dispatch_cb = base->op_imp.base_dispatch; r = (*dispatch_cb)(base,base->dispatch_interval);
base->op_imp.base_dispatch之前在epoll_init里完成过初始化
其实调用的是epoll的dispatch
1 | static int epoll_dispatch(iop_base_t * base, int timeout) |
这句话完成绑定在iop的回调函数调用,基本功能就是accept,read或者write等
//这个宏是调用绑定在iop的事件回调函数(accept,read,write等)IOP_CB(base,iop,from_epoll_events(iop_data->events[i].events));
这样就是整个libiop通讯流程和事件驱动机制