最近朋友推荐,学习了libiop这个网络库,作者封装的很全面,代码很简洁

适合初学者学习基于事件驱动的网络io

先看看iop_def.h, 这里面定义了常用的数据结构

tag_iop_base_t 主要用于管理所有事件,每个事件是一个iop_t,

maxio表示最大的文件描述符,

free_list_head 表示可用的空闲列表头部id,一般用iops + free_list_head

取出iop_t 的元素

同理free_list_tail,最后一个可用iop,

iop_op_t 是封装了几个函数指针的结构体,

包括网络模型的名字,事件的添加,事件的删除,事件的更改,事件的派发

剩下的如注释所示

  1. struct tag_iop_base_t
  2. {
  3. iop_t *iops; /*所有iop*/
  4. int maxio; /*最大并发io数,包括定时器在内*/
  5. int maxbuf; /*单个发送或接收缓存的最大值*/
  6. int free_list_head; /*可用iop列表*/
  7. int free_list_tail; /*最后一个可用iop*/
  8. int io_list_head; /*已用io类型的iop列表*/
  9. int timer_list_head; /*已用timer类型的iop列表*/
  10. int connect_list_head; /*异步连接的iop列表*/
  11. volatile int exit_flag; /*退出标志*/
  12.  
  13. int dispatch_interval; /*高度的间隔时间*/
  14. iop_op_t op_imp; /*事件模型的内部实现*/
  15. void *model_data; /*事件模型特定的数据*/
  16.  
  17. iop_time_t cur_time; /*当前调度时间*/
  18. iop_time_t last_time; /*上次调度时间*/
  19. iop_time_t last_keepalive_time; /*上次检查keepalive的时间*/
  20.  
  21. _list_node_t * tcp_protocol_list_head; /*use for advance tcp server model.*/
  22. };

看一下iop_t结构体,id是从0开始到n的数,这个是在tag_iop_base_t 中初始化队列时做的,

io_handle_t是这个结构存储的socket id, iop_type分三种0表示释放,1表示io读写,2表示

定时器事件, iop_event_cb表示事件回调函数指针,每一个iop_t绑定了不同的回调函数,

比如accept,比如read,比如write,但是这些回调函数要封装成iop_event_cb类型,

dbuf_t 是作者封装的一个管理发送和接受数据的结构

  1. /*
  2. *tag_iop_t:iop结构,每一个iop对象都会对应一个tag_iop_t结构
  3. */
  4. struct tag_iop_t
  5. {
  6. int id; /*对应的id*/
  7. io_handle_t handle; /*关联的句柄*/
  8. int iop_type; /*对象类型:0:free,1:io,2:timer*/
  9. int prev; /*上一个对象*/
  10. int next; /*下一个对象*/
  11. unsigned int events; /*关注的事件*/
  12. int timeout; /*超时值*/
  13. iop_event_cb evcb; /*事件回调*/
  14. void *arg; /*用户指定的参数,由用户负责释放资源*/
  15. void *sys_arg; /*系统指定的参数,系统自动释放资源*/
  16. /*以下字段对定时器无用*/
  17. dbuf_t *sbuf; /*发送缓存区*/
  18. dbuf_t *rbuf; /*接收缓存区*/
  19. iop_time_t last_dispatch_time; /*上次调度的时间*/
  20. };

iop_event_cb 定义如下

  1. /*事件回调函数,返回-1代表要删除对象,返回0代表正常*/
  2. typedef int (*iop_event_cb)(iop_base_t *,int,unsigned int,void *);

dbuf_t结构如下

  1. struct tag_dbuf
  2. {
  3. unsigned int capacity;
  4. unsigned int size;
  5. void *data;
  6. };

至于dbuf_t如何开辟空间释放空间,读写偏移的都不做赘述

iop_base_t中iop_op_t 结构很重要,是事件调度的核心

结构如下

  1. struct tag_iop_op_t
  2. {
  3. const char *name; //模型名称
  4. void (*base_free)(iop_base_t *); //资源释放的接口
  5. int (*base_dispatch)(iop_base_t *, int); //模型调度接口
  6. //添加事件
  7. int (*base_add)(iop_base_t *, int, io_handle_t, unsigned int);
  8. //删除事件
  9. int (*base_del)(iop_base_t *, int,io_handle_t);
  10. //修改事件
  11. int (*base_mod)(iop_base_t *, int, io_handle_t, unsigned int);
  12. };

因为对应不同的平台,我们要应用不同的网络模型,比如epoll,select,iocp等等。

但是对于异步通信IO我们采取事件回调机制,也就是说提前绑定好读事件,写事件等,

在循环中调用base_dispatch函数指针,就可以实现对于不同模型的派发。

上面就是libiop模型的基本结构和框架

我们看下epoll模型的封装

tag_epoll_data 是封装的epoll基本结构,

这个结构存在iop_base_t的model_data里

  1. struct tag_epoll_data {
  2. struct epoll_event *events; //监听的epoll_events 队列
  3. int nevents; //epoll_events 事件大小
  4. int epfd; //epoll_create 产生的epoll表句柄
  5. };

两个函数,iop_t应用层的读写宏

  1. EV_TYPE_READ
  1. EV_TYPE_WRITE
    epoll的读写宏
  1. EPOLLINEPOLLOUT互相转换
  1. static uint32_t to_epoll_events(uint32_t what)
  2. {
  3. uint32_t events=;
  4. if(what & EV_TYPE_READ)
  5. {
  6. events = EPOLLIN;
  7. }
  8. if(what & EV_TYPE_WRITE)
  9. {
  10. events |= EPOLLOUT;
  11. }
  12. return events;
  13. }
  14.  
  15. static uint32_t from_epoll_events(uint32_t events)
  16. {
  17. uint32_t what=;
  18. if(events & (EPOLLHUP|EPOLLERR))
  19. {
  20. what = EV_TYPE_READ | EV_TYPE_WRITE;
  21. }
  22. else
  23. {
  24. if(events & EPOLLIN){what |= EV_TYPE_READ;}
  25. if(events & EPOLLOUT){what |= EV_TYPE_WRITE;}
  26. }
  27. return what;
  28. }

初始化epoll结构和数据

  1. int iop_init_epoll(void *iop_base, int maxev)
  2. {
  3. iop_base_t *base = (iop_base_t *)iop_base;
  4. //iop_base 事 件 操作结构体
  5.  
  6. //iop_base_t中op_imp取出模型抽象的结构体
  7. iop_op_t *iop_op = &(base->op_imp);
  8. //开辟epoll_data空间
  9. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(malloc(sizeof(iop_epoll_data_t)));
  10. if(!iop_data)
  11. {
  12. return -;
  13. }
  14. //监听的队列大小为maxev
  15. iop_data->nevents = maxev;
  16. //为epll_data里监听事件队列开辟连续空间
  17. iop_data->events = (struct epoll_event *)(malloc(sizeof(struct epoll_event) * maxev));
  18. if(!iop_data)
  19. {
  20. free(iop_data);
  21. return -;
  22. }
  23.  
  24. //模型内部实现,不同模型不同的函数指针和名字
  25. iop_op->name = "epoll";
  26. iop_op->base_free = epoll_free;
  27. iop_op->base_dispatch = epoll_dispatch;
  28. iop_op->base_add = epoll_add;
  29. iop_op->base_del = epoll_del;
  30. iop_op->base_mod = epoll_mod;
  31.  
  32. //1024 is not the max events limit.
  33. //创建epoll表句柄
  34. int epfd = epoll_create();
  35. if(epfd < )
  36. {
  37. free(iop_data->events);
  38. free(iop_data);
  39. free(iop_op);
  40. return -;
  41. }
  42. iop_data->epfd = epfd;
  43.  
  44. //iop_epoll_data_t类型的数据存在base的model_data里
  45. //方便回调
  46. base->model_data = iop_data;
  47.  
  48. return ;
  49. }

对应的释放epoll开辟的空间和数据

  1. //epoll 释放
  2. static void epoll_free(iop_base_t *base)
  3. {
  4. //model_data里存放了epoll数据的指针
  5. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
  6. if(!iop_data){return;}
  7. //释放events队列
  8. if(iop_data->events)
  9. {
  10. free(iop_data->events);
  11. }
  12. //关闭iop_data->epfd
  13. if(iop_data->epfd >= )
  14. {
  15. close(iop_data->epfd);
  16. }
  17. free(iop_data);
  18. base->model_data = (void *);
  19. }

epoll 添加事件

  1. //epoll添加事件
  2. //base 为iop_base回传指针
  3. //id为iop的id
  4. //io_handle_t 为socket
  5. //events 为事件类型(EV_TYPE_READ或者EV_TYPE_WRITE)
  6. static int epoll_add(iop_base_t *base, int id, io_handle_t handle, unsigned int events)
  7. {
  8. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
  9. struct epoll_event ev;
  10. ev.data.u32 = id;
  11. //转换为EPOLLIN或者EPOLLOUT
  12. ev.events = to_epoll_events(events);
  13. //iop_set_nonblock(handle);
  14. return epoll_ctl(iop_data->epfd, EPOLL_CTL_ADD, (int)handle, &ev);
  15. }

epoll删除事件

  1. //epoll删除事件
  2. //base 为iop_base回传指针
  3. //id为iop的id
  4. //io_handle_t 为socket
  5. static int epoll_del(iop_base_t *base, int id,io_handle_t handle)
  6. {
  7. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
  8. struct epoll_event ev;
  9. ev.data.u32 = id;
  10. ev.events = ;
  11. //ev回传进去,删除epoll_events中socket为handle的注册事件
  12. return epoll_ctl(iop_data->epfd, EPOLL_CTL_DEL, (int)handle, &ev);
  13. }

epoll事件更改

  1. //epoll 模式更改(读写更改)
  2. static int epoll_mod(iop_base_t *base, int id, io_handle_t handle, unsigned int events)
  3. {
  4. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
  5. struct epoll_event ev;
  6. ev.data.u32 = id;
  7. ev.events = to_epoll_events(events);
  8. return epoll_ctl(iop_data->epfd, EPOLL_CTL_MOD, (int)handle, &ev);
  9. }

epoll事件派发

  1. //epoll 事件派发
  2. static int epoll_dispatch(iop_base_t * base, int timeout)
  3. {
  4. int i;
  5. int id = ;
  6. iop_t *iop = NULL;
  7. //iop_base中取出模型数据
  8. iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
  9. int n = ;
  10. do{
  11. n = epoll_wait(iop_data->epfd, iop_data->events, iop_data->nevents, timeout);
  12. }while((n < ) && (errno == EINTR));
  13. base->cur_time = time(NULL);
  14. for(i = ; i < n; i++)
  15. {
  16. //取出iop的id
  17. id = (int)((iop_data->events)[i].data.u32);
  18. if(id >= && id < base->maxio)
  19. {
  20. iop = (base->iops)+id;
  21. //这个宏是调用绑定在iop的事件回调函数(accept,read,write等)
  22. IOP_CB(base,iop,from_epoll_events(iop_data->events[i].events));
  23. }
  24. }
  25. return n;
  26. }

以上就是libiop事件驱动的核心结构和设计,做个简单的总结,如果我们要设计一个多路复用的事件驱动

基本结构是这样的

//eventEle是应用层管理的最小单元

  1. int (*WRAFuc )(eventLoop* eventLoopP, int id, int mask, ...);

//mask为应用层自己定义的读写标记

  1. struct eventEle
  2.  
  3. {
  4.  
  5. int socket; //关联的socket
  6.  
  7. WRAFuc mPfunc; //读写接受等功能回调的函数
  8.  
  9. //读写缓冲区可自己封装
  10.  
  11. char readBuf[]; //读缓冲区
  12.  
  13. char writeBuff[]; //写缓冲区
  14.  
  15. };

//事件轮询的基本结构

  1. struct eventLoop
  2.  
  3. {
  4.  
  5. eventEle * eventList;
  6.  
  7. int maxfd;
  8.  
  9. int lastActiveTime;
  10.  
  11. iop_op_t op_imp; /*事件模型的内部实现*/
  12.  
  13. void * model_data; /*void 指针指向开辟的不同模型的数据*/
  14.  
  15. };

不同模型的操作进行封装成一个结构体,

结构体里面有添加,删除,更改,派发,释放的函数指针

  1. struct tag_iop_op_t
  2. {
  3. const char *name; //模型名称
  4. void (*base_free)(iop_base_t *); //资源释放的接口
  5. int (*base_dispatch)(iop_base_t *, int); //模型调度接口
  6. //添加事件
  7. int (*base_add)(iop_base_t *, int, io_handle_t, unsigned int);
  8. //删除事件
  9. int (*base_del)(iop_base_t *, int,io_handle_t);
  10. //修改事件
  11. int (*base_mod)(iop_base_t *, int, io_handle_t, unsigned int);
  12. };

这就是设计一个基本的事件驱动网络库的基本思路,

源代码下载地址:http://download.csdn.net/detail/secondtonone1/9517689

我的公众号:

libiop网络库数据结构和基础知识的更多相关文章

  1. 数据结构&&算法基础知识

    写本篇主要是为了将基础知识梳理一遍,天天加一些基本东西,以后复习时可以返回来看看. 数据结构&&基础算法: 基本算法: 二分查找 二叉树: 二叉树的各种遍历 位操作: 排序: 排序算法 ...

  2. Java网络编程一:基础知识详解

    网络基础知识 1.OSI分层模型和TCP/IP分层模型的对应关系 这里对于7层模型不展开来讲,只选择跟这次系列主题相关的知识点介绍. 2.七层模型与协议的对应关系 网络层   ------------ ...

  3. socket网络编程的一些基础知识

    源地址:http://blog.csdn.net/roger_77/article/details/1453049 目录: 1) 什么是套接字? 2) Internet 套接字的两种类型 3) 网络理 ...

  4. python复杂网络库networkx:基础

    http://blog.csdn.net/pipisorry/article/details/49839251 其它复杂网络绘图库 [SNAP for python] [ArcGIS,Python,网 ...

  5. python科学计算库的numpy基础知识,完美抽象多维数组(原创)

    #导入科学计算库 #起别名避免重名 import numpy as np #小技巧:从外往内看==从左往右看 从内往外看==从右往左看 #打印版本号 print(np.version.version) ...

  6. 大话数据结构–1.基础知识+2.算法

      2.算法: 算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每个指令表现为一个或多个操作. 特性:输入.输出.有穷性.确定性.可行性.   2.9.1.算法时间复杂度: 语句 ...

  7. TCP/IP网络协议基础知识集锦[转]

    引言 本篇属于TCP/IP协议的基础知识,重点介绍了TCP/IP协议簇的内容.作用以及TCP.UDP.IP三种常见网络协议相关的基础知识. 内容 TCP/IP协议簇是由OSI七层模型发展而来的,之所以 ...

  8. TCP/IP基础知识

    TCP/IP基础知识 网络 TCP/IP 引言 本篇属于TCP/IP协议的基础知识,重点介绍了TCP/IP协议簇的内容.作用以及TCP.UDP.IP三种常见网络协议相关的基础知识. 内容 TCP/IP ...

  9. 基于c++11新标准开发一个支持多线程高并发的网络库

    背景 新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间. 之前我也写过基于ACE的网络server框架,但A ...

随机推荐

  1. leetcode个人题解——#34 Find First and Last Position of Element in Sorted Array

    思路:先二分查找到一个和target相同的元素,然后再左边二分查找左边界,右边二分查找有边界. class Solution { public: , end = -; int ends; int lS ...

  2. Amazon.com 购物 信用卡预售期

    I understand and thanks for confirming. In this case, the $1.00 is not a charge.  It is an authoriza ...

  3. zookeeper的选举过程

    zookeeper的选举过程大致如下: zookeeper的选举过程,就是选出一个在n/2+1个节点中选出一个节点为主节点的过程.比如,当我们启动一个有5个节点的zookeeper集群的时候.首先启动 ...

  4. Python中用字符串导入module

    在Python中,无法通过字符串来导入一个module文件: import "string" # Error x = "string" import x # 不 ...

  5. 谈谈javascript中的变量提升还有函数提升

    在很多面试题中,经常会看到关于变量提升,还有函数提升的题目,所以我就写一篇自己理解之后的随笔,方便之后的查阅和复习. 首先举个例子 foo();//undefined function foo(){ ...

  6. “Hello World!团队”Beta发布—视频链接+文案+美工

    视频链接:http://v.youku.com/v_show/id_XMzE3MjEyMzkyMA==.html?spm=a2h3j.8428770.3416059.1 文案+美工:http://ww ...

  7. VMware提示无法打开内核设备 \\.\Global\vmx86: 系统找不到指定的文件解决方案

    1.右键单击[我的电脑],选择[管理] 2.在[服务]中找到VMware Workstation Server服务右键启动

  8. MYSQL报警:Warning: Using a password on the command line interface can be insecure.

    问题描述:执行下面的语句,sql是执行成功了,但是出现了一个报警,报警看上去始终不舒服 mysql -hip -Pport -uuser -ppassword -e "use db;dele ...

  9. 结对项目之对PIE的测试程序

    项目要求: 构造程序,分别是: 不能触发Fault. 触发Fault,但是不能触发Error. 触发Error,但是不能产生Failure. 结对对象:陈秋月  学号:2013110404  博客地址 ...

  10. 什么是HotSpot

    Java 是动态编译,跟C++静态编译不同,这就是JIT编译器的原因(Just In Time) HotSpot会把这些部门动态地编译成机器码,Native code, 并对机器码进行优化, 静态编译 ...