简介
函数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;
}测试

 
 



















