Libevent实现server的三种方法,原生socket event 、bufferevent 、evconnlistener_new_bind

参考文章
可以用上篇文章的poll client进行测试

bufferevent 帮我们更好的处理单纯的读写操作
evconnlistener_new_bind内部帮我们使用了socket的accept bind等函数
带有定时器超过时间没有读写操作就将断开连接。
bufferevent_set_timeouts

#include <iostream>
#include <curl/curl.h>
#include <assert.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/thread.h>
#include <sys/types.h>
#include <error.h>
#include <unistd.h>
#include <string.h>


void event_cb(struct bufferevent* bev, short event, void * arg )
{
    if ( event & BEV_EVENT_TIMEOUT )
        printf("client timeout\n");
    else if ( event & BEV_EVENT_EOF )
        printf("connection closed\n");
    else if ( event & BEV_EVENT_ERROR )
        printf("some other error\n");

    bufferevent_free(bev);
}

void socket_read_cb(struct bufferevent* bev, void *arg)
{
    char msg[4096];
    size_t len = bufferevent_read(bev,msg,sizeof(msg));
    msg[len] = '\0';
    printf("recv the client msg: %s\n",msg);

    char reply_msg[4096] = " received the msg : ";

    strcat(reply_msg+ strlen(reply_msg),msg);
    bufferevent_write(bev,reply_msg, strlen(reply_msg));
}

void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
                 struct sockaddr*sock, int socklen, void*arg)
{
    printf("accapt a client %d \n",fd);
    struct event_base* base = (struct event_base *)arg;
    struct bufferevent *bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev,socket_read_cb,NULL,event_cb,NULL);
    bufferevent_enable(bev,EV_READ | EV_PERSIST);
    struct timeval tv = {10,0};
    bufferevent_set_timeouts (bev, &tv, 0);
}

typedef struct sockaddr SA;
int tcp_server_init(int port, int listen_num)
{
    int errno_save;
    evutil_socket_t listener;

    listener = ::socket(AF_INET, SOCK_STREAM, 0);
    if( listener == -1 )
        return -1;

    //允许多次绑定同一个地址。要用在socket和bind之间
    evutil_make_listen_socket_reuseable(listener);

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port = htons(port);

    if( ::bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
        goto error;

    if( ::listen(listener, listen_num) < 0)
        goto error;


    //跨平台统一接口,将套接字设置为非阻塞状态
    evutil_make_socket_nonblocking(listener);

    return listener;

    error:
    errno_save = errno;
    evutil_closesocket(listener);
    errno = errno_save;

    return -1;
}

void cmd_msg_cb(int fd, short events, void* arg)
{
    char msg[1024];

    int ret = read(fd, msg, sizeof(msg));
    if( ret <= 0 )
    {
        perror("read fail ");
        exit(1);
    }

    int sockfd = *((int*)arg);

    //把终端的消息发送给服务器端
    //为了简单起见,不考虑写一半数据的情况
    write(sockfd, msg, ret);
}

void socket_read_cb(int fd , short  events , void * arg )
{
    char msg[4096];
    int len = read(fd, msg, sizeof(msg) - 1);

    if(len <= 0)
    {
        printf("some error happen when read\n");
        return;
    }
    msg[len] = '\0';
    printf("recv the client msg : %s\n", msg);
}

void accept_cb(int fd , short events , void * arg )
{
    evutil_socket_t sockfd;

    struct sockaddr_in client;
    socklen_t len = sizeof(client);

    sockfd = ::accept(fd, (struct sockaddr*)&client, &len);
    evutil_make_socket_nonblocking(sockfd);

    printf("accept a client %d\n", sockfd);
    struct event_base* base = (event_base*)arg;
    /*
     * 很堵,被STDIN堵住了
    //动态创建一个event结构体,并将其作为回调参数传递给
    struct event* ev2 = event_new(NULL, -1, 0, NULL, NULL);
    struct event* ev = event_new(NULL, -1, 0, NULL, NULL);
    event_assign(ev2, base, STDIN_FILENO, EV_WRITE  | EV_PERSIST, cmd_msg_cb, (void *)&sockfd);
    event_assign(ev, base, sockfd, EV_READ | EV_PERSIST, socket_read_cb, NULL);
    event_add(ev, NULL);
    event_add(ev2,NULL);
     */
    struct bufferevent* bev = bufferevent_socket_new(base,sockfd,BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(bev,socket_read_cb,NULL, event_cb,arg);
    bufferevent_enable(bev,EV_READ );
}

int main() {
    /*
    int listener = tcp_server_init(5000,10);
    assert(listener != -1 );
    struct event_base *base = event_base_new();
    assert(base != NULL);
    //creatfifo((void*)base);
    struct event* listen_event;
    listen_event = event_new(base,listener,EV_READ|EV_WRITE|EV_PERSIST,accept_cb,(void*)base);
    */
    struct sockaddr_in sin ;
    memset(&sin,0,sizeof(struct  sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(5000);
    struct  event_base *base = event_base_new();
    struct evconnlistener * listener = evconnlistener_new_bind(base,listener_cb,base,
             LEV_OPT_CLOSE_ON_FREE, 10,
            (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
    //监听终端输入事件
    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_base_free(base);
    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值