首页 » 网站推广 » phplibeventlisten技巧_libevent源码分析之bufferevent运用详解

phplibeventlisten技巧_libevent源码分析之bufferevent运用详解

访客 2024-12-01 0

扫一扫用手机浏览

文章目录 [+]

先看看struct bufferevent这个构造体

struct bufferevent {struct event_base ev_base;const struct bufferevent_ops be_ops;struct event ev_read;struct event ev_write;struct evbuffer input;struct evbuffer output;……bufferevent_data_cb readcb;bufferevent_data_cb writecb;bufferevent_event_cb errorcb;……}

可以看出struct bufferevent内置了两个event(读/写)和对应的缓冲区。
当有数据被读入(input)的时候,readcb被调用,当output被输出完成的时候,writecb被调用,当网络I/O涌现缺点,如链接中断,超时或其他缺点时,errorcb被调用。

phplibeventlisten技巧_libevent源码分析之bufferevent运用详解

利用bufferevent的过程:

phplibeventlisten技巧_libevent源码分析之bufferevent运用详解
(图片来自网络侵删)

1. 设置sock为非壅塞的

eg: evutil_make_socket_nonblocking(fd);

2. 利用bufferevent_socket_new创建一个structbufferevent bev,关联该sockfd,托管给event_base

函数原型为:

struct bufferevent bufferevent_socket_new(struct event_base base, evutil_socket_t fd, int options)eg: struct bufferevent bev;bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

3. 设置读写对应的回调函数

函数原型为:

void bufferevent_setcb(struct bufferevent bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void cbarg)eg. bufferevent_setcb(bev, readcb, NULL, errorcb, NULL);

4. 启用读写事宜,实在是调用了event_add将相应读写事宜加入事宜监听行列步队poll。
正如文档所说,如果相应事宜不置为true,bufferevent是不会读写数据的

函数原型:

int bufferevent_enable(struct bufferevent bufev, short event)eg. bufferevent_enable(bev, EV_READ|EV_WRITE);

5. 进入bufferevent_setcb回调函数:

在readcb里面从input中读取数据,处理完毕后添补到output中;

writecb对付做事端程序,只须要readcb就可以了,可以置为NULL;

errorcb用于处理一些缺点信息。

须要C/C++ Linux做事器架构师学习资料私信“资料”(资料包括C/C++,Linux,golang技能,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享

针对这些利用过程进入源码进行剖析:

1. bufferevent_socket_new

(1)在bufferevent_init_common中调用evbuffer_new()初始化input和output

(2)在event_assign中初始化bufferevent中的ev_read和ev_write事宜。

(3)在evbuffer_add_cb中给output添加了一个callback bufferevent_socket_outbuf_cb

2. bufferevent_setcb

该函数的浸染紧张是赋值,把该函数后面的参数,赋值给第一个参数struct bufferevent bufev定义的变量

3. bufferevent_enable

调用event_add将读写事宜加入到事宜监听行列步队中。

对bufferevent常用的几个函数进行剖析:

char evbuffer_readln(struct evbufferbuffer, size_t n_read_out,enum evbuffer_eol_style eol_style);

含义:Read a single line from an evbuffer.

返回值:读到的一行内容

int evbuffer_add(struct evbuffer buf,const void data, size_t datlen);

含义:将数据添加到evbuffer的结尾

返回值:成功返回0,失落败返回-1

int evbuffer_remove(struct evbufferbuf, void data, size_t datlen);

含义:从evbuffer读取数据到data

返回值:成功返回0,失落败返回-1

size_t evbuffer_get_length(const structevbuffer buf);

含义:返回evbuffer中存储的字节长度

暂时先剖析到这里,下面是代码,客户端发送:HTTP/1.0, Client 0 send Message:

Request: Hello Server! over,做事端一条收完成后,会回答:Response ok! Hello Client!

做事端从bufferevent中取出是按行取的。
代码可能有不完善的地方,希望高手提出宝贵见地。

libevent_eventbuffer_server.c

#include <netinet/in.h>#include <sys/socket.h>#include <fcntl.h> #include <event2/event.h>#include <event2/buffer.h>#include <event2/bufferevent.h> #include <assert.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <stdio.h>#include <errno.h> void do_read(evutil_socket_t fd, short events, void arg); //struct bufferevent内建了两个event(read/write)和对应的缓冲区(struct evbuffer input, output),并供应相应的函数用来操作>缓冲区(或者直接操作bufferevent)//吸收到数据后,判断是不一样一条的结束,结束标志为"over"字符串void readcb(struct bufferevent bev, void ctx){ printf("called readcb!\n"); struct evbuffer input, output; char request_line; size_t len; input = bufferevent_get_input(bev);//实在便是取出bufferevent中的input output = bufferevent_get_output(bev);//实在便是取出bufferevent中的output size_t input_len = evbuffer_get_length(input); printf("input_len: %d\n", input_len); size_t output_len = evbuffer_get_length(output); printf("output_len: %d\n", output_len); while(1) { request_line = evbuffer_readln(input, &len, EVBUFFER_EOL_CRLF);//从evbuffer前面取出一行,用一个新分配的空字符结束的字符串返回这一行,EVBUFFER_EOL_CRLF表示行尾是一个可选的回车,后随一个换行符 if(NULL == request_line) { printf("The first line has not arrived yet.\n"); free(request_line);//之以是要进行free是由于 line = mm_malloc(n_to_copy+1)),在这里进行了malloc break; } else{ printf("Get one line date: %s\n", request_line); if(strstr(request_line, "over") != NULL)//用于判断是不是一条的结束 { char response = "Response ok! Hello Client!\r\n"; evbuffer_add(output, response, strlen(response));//Adds data to an event buffer printf("做事端吸收一条数据完成,回答客户端一条: %s\n", response); free(request_line); break; } } free(request_line); } size_t input_len1 = evbuffer_get_length(input); printf("input_len1: %d\n", input_len1); size_t output_len1 = evbuffer_get_length(output); printf("output_len1: %d\n\n", output_len1);} void errorcb(struct bufferevent bev, short error, void ctx){ if (error & BEV_EVENT_EOF) { / connection has been closed, do any clean up here / printf("connection closed\n"); } else if (error & BEV_EVENT_ERROR) { / check errno to see what error occurred / printf("some other error\n"); } else if (error & BEV_EVENT_TIMEOUT) { / must be a timeout event handle, handle it / printf("Timed out\n"); } bufferevent_free(bev);} void do_accept(evutil_socket_t listener, short event, void arg){ struct event_base base = arg; struct sockaddr_storage ss; socklen_t slen = sizeof(ss); int fd = accept(listener, (struct sockaddr)&ss, &slen); if (fd < 0) { perror("accept"); } else if (fd > FD_SETSIZE) { close(fd); } else { struct bufferevent bev; evutil_make_socket_nonblocking(fd); //利用bufferevent_socket_new创建一个struct bufferevent bev,关联该sockfd,托管给event_base BEV_OPT_CLOSE_ON_FREE表示开释bufferevent时关闭底层传输端口。
这将关闭底层套接字,开释底层bufferevent等。
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); //设置读写对应的回调函数 bufferevent_setcb(bev, readcb, NULL, errorcb, NULL);// bufferevent_setwatermark(bev, EV_READ, 0, MAX_LINE); //启用读写事宜,实在是调用了event_add将相应读写事宜加入事宜监听行列步队poll。
正如文档所说,如果相应事宜不置为true,bufferevent是不会读写数据的 bufferevent_enable(bev, EV_READ|EV_WRITE); }} void run(void){ evutil_socket_t listener; struct sockaddr_in sin; struct event_base base; struct event listener_event; base = event_base_new(); if (!base) return; /XXXerr/ sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(8000); listener = socket(AF_INET, SOCK_STREAM, 0); evutil_make_socket_nonblocking(listener); #ifndef WIN32 { int one = 1; setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); }#endif if (bind(listener, (struct sockaddr)&sin, sizeof(sin)) < 0) { perror("bind"); return; }if (listen(listener, 16)<0) { perror("listen"); return; } listener_event = event_new(base, listener, EV_READ|EV_PERSIST, do_accept, (void)base); /XXX check it / event_add(listener_event, NULL); event_base_dispatch(base);} int main(int argc, char argv){ setvbuf(stdout, NULL, _IONBF, 0); run(); return 0;}

编译:gcc -I/usr/include-o test libevent_eventbuffer_server.c -L/usr/local/lib –levent

运行:

做事端:

客户端:

相关文章

招商蛇口中国房地产龙头企业,未来可期

招商蛇口(股票代码:001979),作为中国房地产企业的领军企业,自成立以来始终秉持“以人为本,追求卓越”的经营理念,致力于打造高...

网站推广 2025-02-18 阅读1 评论0