简介
函数bufferevent_new
struct bufferevent *
bufferevent_new(evutil_socket_t fd,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg)
参数说明:
fd:新客户端的文件描述符
readcb:一个函数指针,bufferevent_data_cb类型,读回调函数
writecb:一个函数指针,bufferevent_data_cb类型,写回调函数
eventcb:一个函数指针,bufferevent_event_cb类型,错误回调函数
/** A read or write callback for a bufferevent. The read callback is triggered when new data arrives in the input buffer and the amount of readable data exceed the low watermark which is 0 by default. The write callback is triggered if the write buffer has been exhausted or fell below its low watermark. @param bev the bufferevent that triggered the callback @param ctx the user-specified context for this bufferevent */ typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
/** An event/error callback for a bufferevent. The event callback is triggered if either an EOF condition or another unrecoverable error was encountered. For bufferevents with deferred callbacks, this is a bitwise OR of all errors that have happened on the bufferevent since the last callback invocation. @param bev the bufferevent for which the error condition was reached @param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING to indicate if the error was encountered on the read or write path, and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR, BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED. @param ctx the user-specified context for this bufferevent */ typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
bufferevent_new函数定义
/*
* Create a new buffered event object.
*
* The read callback is invoked whenever we read new data.
* The write callback is invoked whenever the output buffer is drained.
* The error callback is invoked on a write/read error or on EOF.
*
* Both read and write callbacks maybe NULL. The error callback is not
* allowed to be NULL and have to be provided always.
*/
struct bufferevent *
bufferevent_new(evutil_socket_t fd,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg)
{
struct bufferevent *bufev;
if (!(bufev = bufferevent_socket_new(NULL, fd, 0)))
return NULL;
bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg);
return bufev;
}
函数bufferevent_socket_new
struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
int options)
参数说明:
base:事件集合
fd:新客户端的文件描述符
options:可取值enum bufferevent_options枚举。
/** Options that can be specified when creating a bufferevent */ enum bufferevent_options { /** If set, we close the underlying file * descriptor/bufferevent/whatever when this bufferevent is freed. */ BEV_OPT_CLOSE_ON_FREE = (1<<0), /** If set, and threading is enabled, operations on this bufferevent * are protected by a lock */ BEV_OPT_THREADSAFE = (1<<1), /** If set, callbacks are run deferred in the event loop. */ BEV_OPT_DEFER_CALLBACKS = (1<<2), /** If set, callbacks are executed without locks being held on the * bufferevent. This option currently requires that * BEV_OPT_DEFER_CALLBACKS also be set; a future version of Libevent * might remove the requirement.*/ BEV_OPT_UNLOCK_CALLBACKS = (1<<3) };
/**
Create a new socket bufferevent over an existing socket.
@param base the event base to associate with the new bufferevent.
@param fd the file descriptor from which data is read and written to.
This file descriptor is not allowed to be a pipe(2).
It is safe to set the fd to -1, so long as you later
set it with bufferevent_setfd or bufferevent_socket_connect().
@param options Zero or more BEV_OPT_* flags
@return a pointer to a newly allocated bufferevent struct, or NULL if an
error occurred
@see bufferevent_free()
*/
struct bufferevent *
bufferevent_socket_new(struct event_base *base, evutil_socket_t fd,
int options)
{
struct bufferevent_private *bufev_p;
struct bufferevent *bufev;
#ifdef _WIN32
if (base && event_base_get_iocp_(base))
return bufferevent_async_new_(base, fd, options);
#endif
if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL)
return NULL;
if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket,
options) < 0) {
mm_free(bufev_p);
return NULL;
}
bufev = &bufev_p->bev;
evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD);
event_assign(&bufev->ev_read, bufev->ev_base, fd,
EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev);
event_assign(&bufev->ev_write, bufev->ev_base, fd,
EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev);
evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev);
evbuffer_freeze(bufev->input, 0);
evbuffer_freeze(bufev->output, 1);
return bufev;
}
函数bufferevent_setcb
参数同前面的bufferevent_new
void
bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg)
{
BEV_LOCK(bufev);
bufev->readcb = readcb;
bufev->writecb = writecb;
bufev->errorcb = eventcb;
bufev->cbarg = cbarg;
BEV_UNLOCK(bufev);
}
bufferevent_enable函数
int
bufferevent_enable(struct bufferevent *bufev, short event)
参数简介:
bufev:bufferevent_socket_new函数的返回值。
event: 取值是EV_READ 和 EV_WRITE组合。
/**
Enable a bufferevent.
@param bufev the bufferevent to be enabled
@param event any combination of EV_READ | EV_WRITE.
@return 0 if successful, or -1 if an error occurred
@see bufferevent_disable()
*/
int
bufferevent_enable(struct bufferevent *bufev, short event)
{
struct bufferevent_private *bufev_private = BEV_UPCAST(bufev);
short impl_events = event;
int r = 0;
bufferevent_incref_and_lock_(bufev);
if (bufev_private->read_suspended)
impl_events &= ~EV_READ;
if (bufev_private->write_suspended)
impl_events &= ~EV_WRITE;
bufev->enabled |= event;
if (impl_events && bufev->be_ops->enable(bufev, impl_events) < 0)
r = -1;
if (r)
event_debug(("%s: cannot enable 0x%hx on %p", __func__, event, bufev));
bufferevent_decref_and_unlock_(bufev);
return r;
}
bufferevent_read函数
size_t
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
参数说明
同系统read函数对比:
ssize_t read(int fd, void *buf, size_t count);
bufdev:相当于fd
buf:相当于参数data
size:相当于参数count
返回值:出错返回-1,远端关闭时,返回0
size_t
bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
{
return (evbuffer_remove(bufev->input, data, size));
}
bufferevent_event_cb
/**
An event/error callback for a bufferevent.
The event callback is triggered if either an EOF condition or another
unrecoverable error was encountered.
For bufferevents with deferred callbacks, this is a bitwise OR of all errors
that have happened on the bufferevent since the last callback invocation.
@param bev the bufferevent for which the error condition was reached
@param what a conjunction of flags: BEV_EVENT_READING or BEV_EVENT_WRITING
to indicate if the error was encountered on the read or write path,
and one of the following flags: BEV_EVENT_EOF, BEV_EVENT_ERROR,
BEV_EVENT_TIMEOUT, BEV_EVENT_CONNECTED.
@param ctx the user-specified context for this bufferevent
*/
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
what的取值
/** @name Bufferevent event codes
These flags are passed as arguments to a bufferevent's event callback.
@{
*/
#define BEV_EVENT_READING 0x01 /**< error encountered while reading */
#define BEV_EVENT_WRITING 0x02 /**< error encountered while writing */
#define BEV_EVENT_EOF 0x10 /**< eof file reached */
#define BEV_EVENT_ERROR 0x20 /**< unrecoverable error encountered */
#define BEV_EVENT_TIMEOUT 0x40 /**< user-specified timeout reached */
#define BEV_EVENT_CONNECTED 0x80 /**< connect operation finished. */
bufferevent_data_cb
/**
A read or write callback for a bufferevent.
The read callback is triggered when new data arrives in the input
buffer and the amount of readable data exceed the low watermark
which is 0 by default.
The write callback is triggered if the write buffer has been
exhausted or fell below its low watermark.
@param bev the bufferevent that triggered the callback
@param ctx the user-specified context for this bufferevent
*/
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
bufferevent_free函数
和 bufferevent_socket_new或者bufferevent_new成对使用,有分配就有释放,这个函数就是释放资源。
void
bufferevent_free(struct bufferevent *bufev)
{
BEV_LOCK(bufev);
bufferevent_setcb(bufev, NULL, NULL, NULL, NULL);
bufferevent_cancel_all_(bufev);
bufferevent_decref_and_unlock_(bufev);
}
完整实例
源码
#include <sys/types.h>
#include <event2/event-config.h>
#include <event2/listener.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif
/*
*/
struct private_base_data{
struct event_base* base;
};
struct private_client_data{
struct private_base_data* pbd;
struct bufferevent *bev;
int client_socket;
char buf[4096 + 1];
int len;
};
// typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
// typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);
void client_read_bufferevent_data_cb(struct bufferevent *bev, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("readcb %d",pcd->client_socket);
pcd->len = bufferevent_read(bev,pcd->buf,sizeof(pcd->buf) - 1);
DEBUG_INFO("pcd->len = %d",pcd->len);
}
void client_event_bufferevent_event_cb(struct bufferevent *bev, short what, void *ctx){
struct private_client_data *pcd = (struct private_client_data *)ctx;
DEBUG_INFO("eventcb what = %d,0x%02x %s %s %s %s %s %s",what,what,
((what & BEV_EVENT_READING)?"BEV_EVENT_READING":""),
((what & BEV_EVENT_WRITING)?"BEV_EVENT_WRITING":""),
((what & BEV_EVENT_EOF)?"BEV_EVENT_EOF":""),
((what & BEV_EVENT_ERROR)?"BEV_EVENT_ERROR":""),
((what & BEV_EVENT_TIMEOUT)?"BEV_EVENT_TIMEOUT":""),
((what & BEV_EVENT_CONNECTED)?"BEV_EVENT_CONNECTED":"")
);
if(what & BEV_EVENT_EOF){
close(pcd->client_socket);
bufferevent_free(bev);
free(pcd);
}else{
DEBUG_INFO("未知错误");
//即便是未知错误,也关闭连接并释放资源比较好吧
close(pcd->client_socket);
bufferevent_free(bev);
free(pcd);
}
}
void server_evconnlistener_cb(struct evconnlistener *listener, evutil_socket_t new_client, struct sockaddr *addr, int socklen, void *arg)
{
int options = 0;
struct private_base_data *pbd = (struct private_base_data*)arg;
struct sockaddr_in *paddr = (struct sockaddr_in *)addr;
DEBUG_INFO("a new client fd = %d",new_client);
//char *inet_ntoa(struct in_addr in);
DEBUG_INFO("ip = %s,port = %d",inet_ntoa(paddr->sin_addr),ntohs(paddr->sin_port));
options |= BEV_OPT_CLOSE_ON_FREE;
struct bufferevent *bev = bufferevent_socket_new(pbd->base,new_client, options);
if(bev == NULL){
DEBUG_INFO("bufferevent_socket_new error");
exit(-1);
}
struct private_client_data * pcd = (struct private_client_data*)malloc(sizeof(struct private_client_data));
pcd->client_socket = new_client;
bufferevent_setcb(bev,
client_read_bufferevent_data_cb,
NULL,
client_event_bufferevent_event_cb,
pcd);
bufferevent_enable(bev,EV_READ);
}
int main(int argc, char **argv){
struct evconnlistener *listener;
struct sockaddr_in addr;
struct private_base_data *pbd = (struct private_base_data *)malloc(sizeof(struct private_base_data));
pbd->base = event_base_new();
if(pbd->base == NULL){
DEBUG_INFO("Couldn't create event_base");
exit(-1);
}
addr.sin_family = AF_INET;
// addr.sin_addr.s_addr = INADDR_ANY;
// addr.sin_addr.s_addr = inet_addr("0.0.0.0");
// addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_addr.s_addr = inet_addr("192.168.0.11");
addr.sin_port = htons(6666);
listener = evconnlistener_new_bind(
pbd->base,
server_evconnlistener_cb,
pbd,//传给cb的参数,本例中就是server_evconnlistener_cb
LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,
5,//listen的第二个参数
(struct sockaddr*)&addr,//bind的第二个参数
sizeof(addr) //bind的第三个参数
);
if(listener == NULL){
DEBUG_INFO("evconnlistener_new_bind error");
exit(-1);
}
DEBUG_INFO("开始监听端口 %s:%d",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
//开始监听集合中的事件
event_base_dispatch(pbd->base);
evconnlistener_free(listener);
event_base_free(pbd->base);
free(pbd);
DEBUG_INFO("bye bye");
return 0;
}
测试