libevent_server 服务器程序详细注释

来源:互联网 发布:双色球选红球算法 编辑:程序博客网 时间:2024/06/05 11:20
// 引入常用Linux系统头文件 
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>


// 引入libevent 2.x相关的头文件 
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>


//cJOSN引入的头文件
#include "cJSON.h"


// 定义字符串常量,将会回应给Client用 
static const char MESSAGE[] = "Hello, World!\n";
// server监听的端口 
static const int PORT = 9995;


// 定义几个event callback的prototype(原型) 
void listener_cb(struct evconnlistener * , 
        evutil_socket_t,
        struct sockaddr * , 
        int socklen, 
        void * );
void conn_writecb(struct bufferevent * , void * );
void conn_eventcb(struct bufferevent * , short, void * );
void signal_cb(evutil_socket_t, short, void * );




void readcb(struct bufferevent* bev, void * ptr)  
{  
    char buf[1024];  
    int n;  


    //从evbuffer获取数据到bufferevent中
    struct evbuffer* input = bufferevent_get_input(bev);


    //抽取evbuffer中的数据并输出到标准输出
    while ((n = evbuffer_remove(input, buf, sizeof(buf)))>0)  
    {
        fwrite(buf, 1, n, stdout);  
    }  


    cJSON *js = NULL;
    js = cJSON_Parse(buf);
    if(NULL == js)
    {
        perror("js");
        return;
    }
    cJSON *header = cJSON_GetObjectItem(js,"header");
    cJSON *number = cJSON_GetObjectItem(js,"number");
    cJSON *ip = cJSON_GetObjectItem(js,"ip");
    printf("header=%s\n", header->valuestring);
    printf("number=%d\n", number->valueint);
    printf("ip=%s\n", ip->valuestring);


}  


// 监听端口的event callback
void listener_cb(struct evconnlistener * listener, evutil_socket_t fd,struct sockaddr * sa, int socklen, void * user_data)
{
    printf("listener\n");
    struct event_base * base = user_data;
    struct bufferevent * bev;


    // 新建一个bufferevent,设定BEV_OPT_CLOSE_ON_FREE, 
    // 保证bufferevent被free的时候fd也会被关闭 
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if (!bev) 
    {
        fprintf(stderr, "Error constructing bufferevent!");
        event_base_loopbreak(base);
        return;
    }
    // 设定写buffer的event和其它event 
    bufferevent_setcb(bev, readcb, conn_writecb, conn_eventcb, NULL);
    // 开启向fd中写的event 
    bufferevent_enable(bev, EV_WRITE);
    // 关闭从fd中读写入buffer的event 
    //bufferevent_disable(bev, EV_READ);
    //开启向fd中读的event
    bufferevent_enable(bev, EV_READ);
    // 向buffer中写入"Hello, World!\n" 
    // 上面的操作保证在fd可写时,将buffer中的内容写出去 
    bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}




// 每次fd可写,数据非阻塞写入后,会雕也难怪conn_writecb 
// 这个函数每次检查eventbuffer的剩余大小,如果为0 
// 表示数据已经全部写完,将eventbuffer free掉 
// 由于在上面设定了BEV_OPT_CLOSE_ON_FREE,所以fd也会被关闭 
void conn_writecb(struct bufferevent * bev, void * user_data)
{
    struct evbuffer * output = bufferevent_get_output(bev);
    if (evbuffer_get_length(output) == 0)
    {
        printf("flushed answer\n");
        //bufferevent_free(bev);
    }
}


// 处理读、写event之外的event的callback 
void conn_eventcb(struct bufferevent * bev, short events, void * user_data)
{
    if (events & BEV_EVENT_EOF) {
        // Client端关闭连接 
        printf("Connection closed.\n");
    } else if (events & BEV_EVENT_ERROR) {
        // 连接出错 
        printf("Got an error on the connection: %s\n",
                strerror(errno));
    }
    // 如果还有其它的event没有处理,那就关闭这个bufferevent 
    bufferevent_free(bev);
}


// 信号处理event,收到SIGINT (ctrl-c)信号后,延迟2s退出event循环 
void signal_cb(evutil_socket_t sig, short events, void * user_data)
{
    struct event_base * base = user_data;
    struct timeval delay = { 2, 0 };


    printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");


    event_base_loopexit(base, &delay);
}


// 定义标准的main函数 
int main(int argc, char ** argv)
{
    // event_base是整个event循环必要的结构体
    struct event_base * base = event_base_new();


    // 初始化sockaddr_in结构体,监听在0.0.0.0:9995 
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);


    // bind在上面制定的IP和端口,同时初始化listen的事件循环和callback:listener_cb 
    // 并把listener的事件循环注册在event_base:base上 
    struct evconnlistener * listener = NULL;
    listener = evconnlistener_new_bind(base, listener_cb, 
            (void * )base,
            LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
            -1,
            (struct sockaddr*)&sin,
            sizeof(sin));
    if (!listener)
    {
        // 如果发生任何错误,向stderr(标准错误输出)打一条日志,退出 
        fprintf(stderr, "Could not create a listener!\n");
        return 1;
    }
#if 0
    // 创建并初始化信号处理event 
    struct event *signal_event = evsignal_new(base, SIGINT, signal_cb, (void * )base);


    //把这个callback放入base中 
    if (!signal_event || event_add(signal_event, NULL)<0)
    {
        fprintf(stderr, "Could not create/add a signal event!\n");
        return 1;
    }
#endif
    // 程序将在下面这一行内启动event循环,只有在调用event_base_loopexit后 
    // 才会从下面这个函数返回,并向下执行各种清理函数,导致整个程序退出 
    event_base_dispatch(base);


    // 各种清理free 
    evconnlistener_free(listener);
    // event_free(signal_event);
    event_base_free(base);


    printf("done\n");
    return 0;
}
0 0
原创粉丝点击