libiop网络库数据结构和基础知识
最近朋友推荐,学习了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 是封装了几个函数指针的结构体,
包括网络模型的名字,事件的添加,事件的删除,事件的更改,事件的派发
剩下的如注释所示
struct tag_iop_base_t
{
iop_t *iops; /*所有iop*/
int maxio; /*最大并发io数,包括定时器在内*/
int maxbuf; /*单个发送或接收缓存的最大值*/
int free_list_head; /*可用iop列表*/
int free_list_tail; /*最后一个可用iop*/
int io_list_head; /*已用io类型的iop列表*/
int timer_list_head; /*已用timer类型的iop列表*/
int connect_list_head; /*异步连接的iop列表*/
volatile int exit_flag; /*退出标志*/ int dispatch_interval; /*高度的间隔时间*/
iop_op_t op_imp; /*事件模型的内部实现*/
void *model_data; /*事件模型特定的数据*/ iop_time_t cur_time; /*当前调度时间*/
iop_time_t last_time; /*上次调度时间*/
iop_time_t last_keepalive_time; /*上次检查keepalive的时间*/ _list_node_t * tcp_protocol_list_head; /*use for advance tcp server model.*/
};
看一下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 是作者封装的一个管理发送和接受数据的结构
/*
*tag_iop_t:iop结构,每一个iop对象都会对应一个tag_iop_t结构
*/
struct tag_iop_t
{
int id; /*对应的id*/
io_handle_t handle; /*关联的句柄*/
int iop_type; /*对象类型:0:free,1:io,2:timer*/
int prev; /*上一个对象*/
int next; /*下一个对象*/
unsigned int events; /*关注的事件*/
int timeout; /*超时值*/
iop_event_cb evcb; /*事件回调*/
void *arg; /*用户指定的参数,由用户负责释放资源*/
void *sys_arg; /*系统指定的参数,系统自动释放资源*/
/*以下字段对定时器无用*/
dbuf_t *sbuf; /*发送缓存区*/
dbuf_t *rbuf; /*接收缓存区*/
iop_time_t last_dispatch_time; /*上次调度的时间*/
};
iop_event_cb 定义如下
/*事件回调函数,返回-1代表要删除对象,返回0代表正常*/
typedef int (*iop_event_cb)(iop_base_t *,int,unsigned int,void *);
dbuf_t结构如下
struct tag_dbuf
{
unsigned int capacity;
unsigned int size;
void *data;
};
至于dbuf_t如何开辟空间释放空间,读写偏移的都不做赘述
iop_base_t中iop_op_t 结构很重要,是事件调度的核心
结构如下
struct tag_iop_op_t
{
const char *name; //模型名称
void (*base_free)(iop_base_t *); //资源释放的接口
int (*base_dispatch)(iop_base_t *, int); //模型调度接口
//添加事件
int (*base_add)(iop_base_t *, int, io_handle_t, unsigned int);
//删除事件
int (*base_del)(iop_base_t *, int,io_handle_t);
//修改事件
int (*base_mod)(iop_base_t *, int, io_handle_t, unsigned int);
};
因为对应不同的平台,我们要应用不同的网络模型,比如epoll,select,iocp等等。
但是对于异步通信IO我们采取事件回调机制,也就是说提前绑定好读事件,写事件等,
在循环中调用base_dispatch函数指针,就可以实现对于不同模型的派发。
上面就是libiop模型的基本结构和框架
我们看下epoll模型的封装
tag_epoll_data 是封装的epoll基本结构,
这个结构存在iop_base_t的model_data里
struct tag_epoll_data {
struct epoll_event *events; //监听的epoll_events 队列
int nevents; //epoll_events 事件大小
int epfd; //epoll_create 产生的epoll表句柄
};
两个函数,iop_t应用层的读写宏
EV_TYPE_READ和
EV_TYPE_WRITE
epoll的读写宏
EPOLLIN和EPOLLOUT互相转换
static uint32_t to_epoll_events(uint32_t what)
{
uint32_t events=;
if(what & EV_TYPE_READ)
{
events = EPOLLIN;
}
if(what & EV_TYPE_WRITE)
{
events |= EPOLLOUT;
}
return events;
} static uint32_t from_epoll_events(uint32_t events)
{
uint32_t what=;
if(events & (EPOLLHUP|EPOLLERR))
{
what = EV_TYPE_READ | EV_TYPE_WRITE;
}
else
{
if(events & EPOLLIN){what |= EV_TYPE_READ;}
if(events & EPOLLOUT){what |= EV_TYPE_WRITE;}
}
return what;
}
初始化epoll结构和数据
int iop_init_epoll(void *iop_base, int maxev)
{
iop_base_t *base = (iop_base_t *)iop_base;
//iop_base 事 件 操作结构体 //iop_base_t中op_imp取出模型抽象的结构体
iop_op_t *iop_op = &(base->op_imp);
//开辟epoll_data空间
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(malloc(sizeof(iop_epoll_data_t)));
if(!iop_data)
{
return -;
}
//监听的队列大小为maxev
iop_data->nevents = maxev;
//为epll_data里监听事件队列开辟连续空间
iop_data->events = (struct epoll_event *)(malloc(sizeof(struct epoll_event) * maxev));
if(!iop_data)
{
free(iop_data);
return -;
} //模型内部实现,不同模型不同的函数指针和名字
iop_op->name = "epoll";
iop_op->base_free = epoll_free;
iop_op->base_dispatch = epoll_dispatch;
iop_op->base_add = epoll_add;
iop_op->base_del = epoll_del;
iop_op->base_mod = epoll_mod; //1024 is not the max events limit.
//创建epoll表句柄
int epfd = epoll_create();
if(epfd < )
{
free(iop_data->events);
free(iop_data);
free(iop_op);
return -;
}
iop_data->epfd = epfd; //iop_epoll_data_t类型的数据存在base的model_data里
//方便回调
base->model_data = iop_data; return ;
}
对应的释放epoll开辟的空间和数据
//epoll 释放
static void epoll_free(iop_base_t *base)
{
//model_data里存放了epoll数据的指针
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
if(!iop_data){return;}
//释放events队列
if(iop_data->events)
{
free(iop_data->events);
}
//关闭iop_data->epfd
if(iop_data->epfd >= )
{
close(iop_data->epfd);
}
free(iop_data);
base->model_data = (void *);
}
epoll 添加事件
//epoll添加事件
//base 为iop_base回传指针
//id为iop的id
//io_handle_t 为socket
//events 为事件类型(EV_TYPE_READ或者EV_TYPE_WRITE)
static int epoll_add(iop_base_t *base, int id, io_handle_t handle, unsigned int events)
{
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
struct epoll_event ev;
ev.data.u32 = id;
//转换为EPOLLIN或者EPOLLOUT
ev.events = to_epoll_events(events);
//iop_set_nonblock(handle);
return epoll_ctl(iop_data->epfd, EPOLL_CTL_ADD, (int)handle, &ev);
}
epoll删除事件
//epoll删除事件
//base 为iop_base回传指针
//id为iop的id
//io_handle_t 为socket
static int epoll_del(iop_base_t *base, int id,io_handle_t handle)
{
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
struct epoll_event ev;
ev.data.u32 = id;
ev.events = ;
//ev回传进去,删除epoll_events中socket为handle的注册事件
return epoll_ctl(iop_data->epfd, EPOLL_CTL_DEL, (int)handle, &ev);
}
epoll事件更改
//epoll 模式更改(读写更改)
static int epoll_mod(iop_base_t *base, int id, io_handle_t handle, unsigned int events)
{
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
struct epoll_event ev;
ev.data.u32 = id;
ev.events = to_epoll_events(events);
return epoll_ctl(iop_data->epfd, EPOLL_CTL_MOD, (int)handle, &ev);
}
epoll事件派发
//epoll 事件派发
static int epoll_dispatch(iop_base_t * base, int timeout)
{
int i;
int id = ;
iop_t *iop = NULL;
//iop_base中取出模型数据
iop_epoll_data_t *iop_data = (iop_epoll_data_t *)(base->model_data);
int n = ;
do{
n = epoll_wait(iop_data->epfd, iop_data->events, iop_data->nevents, timeout);
}while((n < ) && (errno == EINTR));
base->cur_time = time(NULL);
for(i = ; i < n; i++)
{
//取出iop的id
id = (int)((iop_data->events)[i].data.u32);
if(id >= && id < base->maxio)
{
iop = (base->iops)+id;
//这个宏是调用绑定在iop的事件回调函数(accept,read,write等)
IOP_CB(base,iop,from_epoll_events(iop_data->events[i].events));
}
}
return n;
}
以上就是libiop事件驱动的核心结构和设计,做个简单的总结,如果我们要设计一个多路复用的事件驱动
基本结构是这样的
//eventEle是应用层管理的最小单元
int (*WRAFuc )(eventLoop* eventLoopP, int id, int mask, ...);
//mask为应用层自己定义的读写标记
struct eventEle { int socket; //关联的socket WRAFuc mPfunc; //读写接受等功能回调的函数 //读写缓冲区可自己封装 char readBuf[]; //读缓冲区 char writeBuff[]; //写缓冲区 };
//事件轮询的基本结构
struct eventLoop { eventEle * eventList; int maxfd; int lastActiveTime; iop_op_t op_imp; /*事件模型的内部实现*/ void * model_data; /*void 指针指向开辟的不同模型的数据*/ };
不同模型的操作进行封装成一个结构体,
结构体里面有添加,删除,更改,派发,释放的函数指针
struct tag_iop_op_t
{
const char *name; //模型名称
void (*base_free)(iop_base_t *); //资源释放的接口
int (*base_dispatch)(iop_base_t *, int); //模型调度接口
//添加事件
int (*base_add)(iop_base_t *, int, io_handle_t, unsigned int);
//删除事件
int (*base_del)(iop_base_t *, int,io_handle_t);
//修改事件
int (*base_mod)(iop_base_t *, int, io_handle_t, unsigned int);
};
这就是设计一个基本的事件驱动网络库的基本思路,
源代码下载地址:http://download.csdn.net/detail/secondtonone1/9517689
我的公众号:
libiop网络库数据结构和基础知识的更多相关文章
- 数据结构&&算法基础知识
写本篇主要是为了将基础知识梳理一遍,天天加一些基本东西,以后复习时可以返回来看看. 数据结构&&基础算法: 基本算法: 二分查找 二叉树: 二叉树的各种遍历 位操作: 排序: 排序算法 ...
- Java网络编程一:基础知识详解
网络基础知识 1.OSI分层模型和TCP/IP分层模型的对应关系 这里对于7层模型不展开来讲,只选择跟这次系列主题相关的知识点介绍. 2.七层模型与协议的对应关系 网络层 ------------ ...
- socket网络编程的一些基础知识
源地址:http://blog.csdn.net/roger_77/article/details/1453049 目录: 1) 什么是套接字? 2) Internet 套接字的两种类型 3) 网络理 ...
- python复杂网络库networkx:基础
http://blog.csdn.net/pipisorry/article/details/49839251 其它复杂网络绘图库 [SNAP for python] [ArcGIS,Python,网 ...
- python科学计算库的numpy基础知识,完美抽象多维数组(原创)
#导入科学计算库 #起别名避免重名 import numpy as np #小技巧:从外往内看==从左往右看 从内往外看==从右往左看 #打印版本号 print(np.version.version) ...
- 大话数据结构–1.基础知识+2.算法
2.算法: 算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每个指令表现为一个或多个操作. 特性:输入.输出.有穷性.确定性.可行性. 2.9.1.算法时间复杂度: 语句 ...
- TCP/IP网络协议基础知识集锦[转]
引言 本篇属于TCP/IP协议的基础知识,重点介绍了TCP/IP协议簇的内容.作用以及TCP.UDP.IP三种常见网络协议相关的基础知识. 内容 TCP/IP协议簇是由OSI七层模型发展而来的,之所以 ...
- TCP/IP基础知识
TCP/IP基础知识 网络 TCP/IP 引言 本篇属于TCP/IP协议的基础知识,重点介绍了TCP/IP协议簇的内容.作用以及TCP.UDP.IP三种常见网络协议相关的基础知识. 内容 TCP/IP ...
- 基于c++11新标准开发一个支持多线程高并发的网络库
背景 新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间. 之前我也写过基于ACE的网络server框架,但A ...
随机推荐
- jpa的@Query中"?"占位符的使用小坑
今天使用@Query自定义查询语句,出现了一个错误: java.lang.IllegalArgumentException: Parameter with that position [1] did ...
- [leetcode-914-X of a Kind in a Deck of Cards]
In a deck of cards, each card has an integer written on it. Return true if and only if you can choos ...
- react-native debug js remotely跨域问题
react-native debug js remotely跨域问题 我们在安卓真机上调试react-native时,启用debug js remotely的时候,会出现跨域问题.这个时候我们只需要一 ...
- “Hello World!”团队第三周召开的第三次会议
今天是我们团队“Hello World!”团队第三周召开的第三次会议.博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.代码地址 ...
- UVALive - 6916 Punching Robot Lucas+dp
题目链接: http://acm.hust.edu.cn/vjudge/problem/96344 Punching Robot Time Limit: 1000MS64bit IO Format: ...
- ipv6问题
1)百度搜索:针对苹果最新审核要求为应用兼容IPv6 2) ipV6测试网址:http://test-ipv6.com/ http://ipv6.jmu.edu.cn/ http://ipv6test ...
- 代码查重工具sim
在瞎搜东西的时候,发现了一个大牛的博客 看起来很厉害的样子...做了一个LaTeX的语法检查并给出适当的提示,上wiki上一查发现他竟然是CVS第一个版本的发明者和开发者...Dick grune这是 ...
- Ubuntu 下升级 php
起因: 在现有的 Apache + PHP 环境下,增加一个 PHP Extension 扩展时,遇到错误: Unable to initialize moduleModule compiled wi ...
- 【c】线性表
数据对象集:线性表是N(>=0)个元素构成的有序序列,a1,a2,a3.....a(N-1),aN,a(N+1) 线性表上的基本操作有: ⑴ 线性表初始化:Init_List(L)初始条件:表L ...
- [翻译]API Guides - Layouts
官方文档地址:http://developer.android.com/guide/topics/ui/declaring-layout.html PS:API Guides里面的内容不免都简单些,翻 ...