使用Libevent的监听器来搭建一个高端版的回显服务器[2]

时间:2021-02-19 00:14:40

上一篇的客户端还是可以使用的哦,所以在这里我就不敲了使用Libevent的监听器来搭建一个高端版的回显服务器[2]

使用监听器的服务器跟上一篇的服务器稍微有一点点的改动(自动bind,listen,自动accept),主要是调用了这个API,上代码前,先来说说这个API


//头文件是<event2/listener.h>

//返回一个监听器

//base是event_base_new的返回值

//cb是一个回调函数 ,函数原型是void  cb (struct evconnlistener *listener, evutil_socket_t socketfd, struct sockaddr *addr, int addrlen, void *arg);当客户端connect连接成功时调用

//arg是传递给回调函数cb最后一个形参的值

//flag是一些标志,一般我们写LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_EXEC,表示端口可以复用,释放监听器时会自动关闭底层套接字

//backlog是最大未决连接数,说简单点就跟listen函数的第二个参数一样

//addr,addrlen跟bind函数的两个参数是一样的

struct evconnlistener *evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, void *arg, unsigned flags, int backlog,const struct sockaddr *addr, int addrlen);



//说说回调函数cb

//socketfd就是accept产生的socketfd,但是这里的accept底层会自动调用

//addr,addrlen跟accpet后面两个参数是一样的

//arg就是evconnlistener_new_bing传过来的值
void  cb(struct evconnlistener *listener, evutil_socket_t socketfd, struct sockaddr *addr, int addrlen, void *arg);



//下面直接上干货

#include<stdlib.h>

#include<stdio.h>

#include<sys/socket.h>
#include<sys/types.h>
#include<unistd.h>
#include<event2/event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/listener.h>

static int num=0;


void callback_read(struct bufferevent *buffer, void *arg)
{
    char readBuf[4096]={0};
    bufferevent_read(buffer,readBuf,sizeof(readBuf));
    printf("client%d send:%s",(int)arg,readBuf);
    bufferevent_write(buffer,readBuf,sizeof(readBuf));

}


void callback_event(struct bufferevent *buffer, short what, void *arg)
{
    if(what&BEV_EVENT_EOF)
    {
        printf("client%d closed\n",(int)arg);
    }
    else if(what&BEV_EVENT_ERROR)
    {
        printf("some other error\n");
    }
    bufferevent_free(buffer);
}


//当客户端连接成功时候,调用这个函数

void callback_listen(struct evconnlistener *listener, evutil_socket_t socketfd, struct sockaddr *addr, int addrlen, void *arg)
{
    printf("accept produce socketfd is %d\n",socketfd); //socketfd是accept产生的一个套接字,这个套接字是真真用来与客户端进行通信的,不过accept是在底层实现的
    struct event_base *base=(struct event_base *)arg; //arg是evconnlistener_new_bind传过来的值,也就是event_base_new的返回值
    num++;
    printf("client%d connect success......\n",num);
    struct bufferevent *buffer=bufferevent_socket_new(base,socketfd,BEV_OPT_CLOSE_ON_FREE);
    if(buffer==NULL)
    {
        perror("bufferevent_socket_new error");
        return;
    }
    bufferevent_setcb(buffer,callback_read,NULL,callback_event,num);
    bufferevent_enable(buffer,EV_READ|EV_PERSIST);
}


int main(int argc,char  **argv)
{

   struct sockaddr_in addr;
   addr.sin_family=AF_INET;
   addr.sin_port=htons(8080);
   addr.sin_addr.s_addr=INADDR_ANY;
   struct event_base *base=event_base_new();
   if(base==NULL)
   {
       perror("event_base_new error");
       return -1;

   }

    //调用这个函数,会自动bind,listen

    //20是传给listen的值

    //(struct sockaddr*)&addr,sizeof(addr)是传给bind的值

   struct evconnlistener *listener=evconnlistener_new_bind(base,callback_listen,base,
                      LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,20,(struct sockaddr*)&addr,sizeof(addr));
   if(listener==NULL)
   {
       perror("evconnlistener_new error");
       event_base_free(base);
       return -2;
   }
   event_base_dispatch(base);
   event_base_free(base);
   evconnlistener_free(listener);
   return 0;
}