libevent
文章目录
UDP
UDP实现C/S模型
recv()/send() 只能使用TCP通信,替代read\write;
自身就是一个并发处理,本来就是没有建立连接。
server: socket()---->bind()----listen()[可有可无];
while(1){
read()-----被替换----recvfrom();
wtrite()---被替换----sendto()
}
client:
connfd=socket(AF_INET,SOCK_DGRAM,0);
sendto(“服务器地址”,地址结构大小);
recvfrom();
close();
ssize_t recvfrom(int sockfd,void * buf,size_t len ,int flags,
struct sockaddr* src_addr,socklen_t * addrlen);
ssize_t sendto(int sockfd,void * buf,size_t len ,int flags,
const struct sockaddr* dst_addr,socklen_t* addrlen);
本地套接字:
IPC
pipe:应用性最强的
fifo:可以没有血缘关系
mmap:没有血缘且可以输入输出
信号:开销最小的
本地套接字(domain):最稳定的
1.int socket(int domain,int type,int protocol)
domain---AF_UNIX,AF_LOCAL
type-----SOCK_STREAM/SOCK_DGRAM
2. 地址结构:
sockaddr_in ----------------- sockaddr_un
struct sockaddr_in srv_addr----------->struct sockaddr_un srv_addr;
srv_addr.sin_family=AF_INET;---------->sev_addr.sun_family=AF_UNIX;
srv_addr.sin_port=htons(port);-------->strcpy(srv_addr.sun_path,"srv.socket");
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY)----X
bind(fd,(struct sockaddr*)&sev_addr,sizeof(sev_addr))--------
----->(len=2+strlen("srv.socket"))/bind(fd,(struct sockaddr*)&srv_addr),len);
-------len=offsetof(struct sockaddr_un,sun_path)++strlen("srv.socket");(查看一个成员变量在结构中的偏移位置)
3.bind()函数调用成功,会创建一个socket文件(伪文件)。因此为保证bind成功,通常我们在bind之前,可以使用unlink("sev,sock");
4.客服端不能依赖隐式绑定,并且在通讯建立中,创建且初始化2个地址结构(自己的和服务区的);
libevent库
优点:开源 、跨平台、精简。专注网络通信
特征:基于“事件” 异步 通信模型(函数的创建和调用不一样)
与编码包安装:
./configure 检查安装环境 生成makefile
make 生成.o和可执行文件
sudo make install 将必要的资源拷贝至系统指定目录
进入sample,运行demo
编译使用库的.c的时候 需要添加-levent选项 ./a静态库 ./o动态库
看库名 libevent.so---->/usr/local/lib/
libevent框架
创建event_base;
struct event_base * event_base_new(void);
struct event_base * bas=event_base_new();
创建 事件event;
常规事件 event;--->event_new();
带缓冲的事件 bufferevent;--->bufferevent_socket_new();
将事件添加到base上;
int event_add(struct event* ev,const struct timeval*tv );
循环监听事件满足;
int event_base_dispatch(struct event_base* base);
释放event——base;
event_base_free(base);
libevent 常规事件
创建事件
struct event* event_new(struct event_base* base,evutil_socket_t fd,
short what,event_callback_fn cb;void * arg);
fd:绑定在事件上的文件描述符
what:对应发生的事件(响应)(r,w,e) --EV_READ--EV_WRITE--EV_PERSIST持续触发
cb:一旦事件满足监听条件,回调的函数。
typedef void (*event_callback_fn) (evutil_sockt fd,short,void*);
将事件添加到event_base上面:
int event_add(struct event* ev,const struct timeval* tv)
ev:event_new()的返回值
tv:NULL,
-------对应有一个event_del();----用的少,一般不用就直接销毁就可以了
销毁事件
int event_free(struct event* ev);
libevent 未决和非未决
未决:有资格被处理,但是没有被处理
非未决:没有资格处理
libevent bufferevent
创建和释放事件
创建:
struct bufferevent* bufferevent_socket_new(struct event_base *base,evutil_socket_t fd,enum buferrevent_options)
base:event_base
fd:封装到bufferevent内部的fd
option:BEV_OPT_CLOSE_ON_FREE
返回:成功创建的bufferevent事件对象
销毁:
void bufferevent_free()
给读写缓冲区设置回调
对比 event event_new(fd,callback);event_add()---挂到event_base上
bufferevent_socket_new(fd,) + bufferevent_setcb(callback);
设置:
void bufferevent_setcb(struct bufferevent* bufev,
bufferevent_data_cb readcb, //读回调
bufferevent_data_cb writecb, //写回调
bufferevent_data_cb eventcb, //设置回调【可设置NULL】
void *cbarg) //参数
回调函数:
(读)typedf void(*bufferevent_data_cb)(struct bufferevent* bev,void * ctx);
void read_cb(struct bufferevent* bev,void * ctx){
......
bufferevent_read();
}
size_t bufferevent_read(struct bufferevent* bufev,void* buf,size_t busize)
size_t bufferevent_read(struct bufferevent* bufev,const void* buf,size_t busize) (事件)typedf void(*bufferevent_event_cb)(struct bufferevent* bev,short ev,void * ctx); events: BEV_EVENT_CONNETED
缓冲区的设置
void bufferevent_enable(struct bufferevent* bufev,short events)
disable
events:EV_READ EV_WERITE EV_READ|EV_WRITE
默认bufferevent写缓冲是enable,而 读缓冲 是disable;
客户端
connct();-------------------->
int bufferevetn_socket_connet(
struct buuferevent* bev,struct sockaddr* address,int addrlen)
服务端
socke(),bind(),listen(),accept();------------------->
#include<event2/listener.h>
struct evconnlisterner* evconnlistner_new_bind(
struct event_base* base,
evconnlistener_cb cb, // 回调函数
void * ptr, // 回调函数的参数
unsigned flags, //LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE
int backlog, //lieten的第二个参数 -1表示默认最大值
const struct sockaddr* sa //服务器地址
int socklen);
返回一个成功创建的监听器。
typedef void (*evconnlistener_cb)(
struct evconnlistener* listener, //
evutil_socket_t sock, //用于通信的文件描述符
struct sockaddr* addr, //客服端的地址结构
int len, //
void * ptr) //外部ptr传递进来的值
服务器流程
1.创建event_base
2.创建服务器连接监听器 evconnlister_new_bind();
3.在 evconnlister_new_bind 的回调函数中,处理接受连接后的操作
4.回调函数被使用,说明有一个新的客户端来连接上来,会得到一个新的fd,用于客户端通讯(读,写);
5.创建bufferevent事件对象 bufferevent_socket_new(),将fd封装到这个事件对象中
6.使用bufferevent_setcb给这个事件对象的read write event设置回调
7.设置bufferevent的读写缓冲区enable\diable
8.接受、发送数据 bufferevent_read()/bufferevent_write();
9.启动循环监听
10.释放资源
客服端流程
1.创建event_base
2.使用bufferevent_socket_new()创建一个用跟服务器通讯的bufferevent事件对象
3.使用bufferevent_socket_connect()连接服务器
4.使用bufferevent_setcb()给bufferevnet对象的read write event 设置回调
5.设置bufferevent对象的缓冲区 enable \disable
6.接受、发送数据 bufferevent_read()/bufferevent_write();
7.启动循环监听
8.释放资源