使用Libevent常用的API搭建一个回显服务器[1]

来源:互联网 发布:init.gradle windows 编辑:程序博客网 时间:2024/05/16 16:10

上一篇讲了Libevent一些常用的API,但是没有实际的demo,多多少少有点难理解,那么接下来就直接上代码

(执行下面两个命令生成可执行程序)

gcc   client.c   -o   client    -levent_core(指定库名)

export  LD_LIBRARY_PATH=/usr/local/lib(因为event_core在这个目录在,所以要加载该目录下的动态库)


client

#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>



//当向终端输入数据的时候,调用该函数
void callback_input(evutil_socket_t fd, short falg, void *arg)
{
    char buf[4096]={0};
    int len=read(fd,buf,sizeof(buf));//读取终端输入的数据
    if(len==1)
    {
        printf("please input message");
        return;
    }
    bufferevent_write((struct bufferevent*)arg,buf,sizeof(buf));//向服务器发送数据
}


//当服务器发送数据过来的时候,调用该函数
void callback_read(struct bufferevent *buffer, void *arg)
{
    char buf[4096]={0};
    bufferevent_read(buffer,buf,sizeof(buf));//读取服务器发过来的数据
    printf("server send:%s\n",buf);
    printf("please input message to server:");
    fflush(stdout);//刷新终端,这个很重要,不然看不到上面一句话
}


//当服务器关闭的时候,或者bufferevent缓冲区有问题的时候,调用该函数
void callback_event(struct bufferevent *buffer, short what, void *arg)
{
    if(what&BEV_EVENT_EOF)
    {
        printf("connection closed\n");
    }
    else if(what&BEV_EVENT_ERROR)
    {
        printf("some other error\n");
    }
    bufferevent_free(buffer);
}

//客户端初始化函数
int client_init(char *ip,char *port)
{
    evutil_socket_t socketfd=socket(AF_INET,SOCK_STREAM,0);//创建TCP套接字
    if(socketfd<0)
    {
        perror("socket error");
        return -1;
    }
    struct sockaddr_in addr;
    addr.sin_family=AF_INET;//协议族
    addr.sin_port=htons(atoi(port));//将本地端口转化为网络端口
    inet_aton(ip,&addr.sin_addr);//将本地IP,转化为网络IP
    int status=connect(socketfd,(struct sockaddr*)&addr,sizeof(addr));//连接服务器
    if(status!=0)
    {
        perror("connect error");
        return -2;
    }
    evutil_make_socket_nonblocking(socketfd);//设置为非阻塞
    return socketfd;
}

int main(int argc,char **argv)
{
    if(argc<3)
    {
        printf("arguement too less,format is[./a.out ip port]\n"); //表示要这样运行程序  ./a.out  127.0.0.0  8080
        return -1;
    }
    evutil_socket_t socketfd=client_init(argv[1],argv[2]);//初始化,连接服务器
    if(socketfd<0)
    {
        perror("client_init error");
        return -2;
    }
    printf("connect server success......\n");
    struct event_base *base=event_base_new();//创建事件集合,用来管理事件,这是使用Libevent所做的第一步
    if(base==NULL)
    {
        evutil_closesocket(socketfd);//关闭套接字
        perror("event_base_new error");
        return -3;
    }
    struct bufferevent *buffer=bufferevent_socket_new(base,socketfd,BEV_OPT_CLOSE_ON_FREE);//创建一个基于socket的bufferevent缓冲区,利用产生的bufferevent进行读写操作,BEV_OPT_CLOSE_ON_FREE表示释放 bufferevent 时关闭底层传输端口
    if(buffer==NULL)
    {
        evutil_closesocket(socketfd);
        perror("bufferevent_socket_new error");
        return -4;
    }
    printf("please input message to server:");
    fflush(stdout);
    struct event *event=event_new(base,STDIN_FILENO,EV_READ|EV_PERSIST,callback_input,buffer);//注册终端响应事件,当往终端输入数据的时候会调用input函数
    if(event==NULL)
    {
        evutil_closesocket(socketfd);
        bufferevent_free(buffer);//释放bufferevent
        perror("event_new error");
        return -5;
    }
    event_add(event,NULL);//将注册的事件变为未决状态
    bufferevent_setcb(buffer,callback_read,NULL,callback_event,event);//当bufferevent缓冲区有内容可以读取/出现问题的时候调用read/event回调函数
    bufferevent_enable(buffer,EV_READ|EV_PERSIST);//启用回调水位
    event_base_dispatch(base);//循环
    event_free(event);//释放event
    event_base_free(base);//释放base

}



server(因为上面写了很多备注,下面就不写咯微笑

#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/util.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));
}


//当客户端关闭或者bufferevent缓冲区有问题的时候,调用该函数
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_accept(evutil_socket_t fd, short flag, void *arg)
{


    struct event_base *base=(struct event_base *)arg;
    int socketfd=accept(fd,NULL,NULL);
    if(socketfd<0)
    {
        perror("accept error");
        return;
    }
    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 server_init(int port,int listennum)
{
    int listenfd=socket(AF_INET,SOCK_STREAM,0);
    if(listenfd<0)
    {
        perror("socker error");
        return -1;
    }
    evutil_make_listen_socket_reuseable(listenfd);//端口可以重复绑定
    struct sockaddr_in addr;
    addr.sin_port=htons(port);
    addr.sin_family=AF_INET;
    addr.sin_addr.s_addr=INADDR_ANY;//任何client都可以访问,不指定IP,这里也可以写0
    int status=bind(listenfd,(struct sockaddr *)&addr,sizeof(addr));//绑定套接字
    if(status!=0)
        goto Error;
    status=listen(listenfd,listennum);//开始监听
    if(status!=0)
        goto Error;
    evutil_make_socket_nonblocking(listenfd);
    return listenfd;
    Error:
    printf("error");
    evutil_closesocket(listenfd);
    return -2;


}


int main(int argc,char  **argv)
{
    evutil_socket_t listenfd=server_init(8080,20);//服务器初始化,端口为8080,listen个数为20
    if(listenfd<0)
    {
        perror("server_init error");
        return -1;
    }
   struct event_base *base=event_base_new();
   if(base==NULL)
   {
       perror("event_base_new error");
       return -2;
   }
   struct event * event=event_new(base,listenfd,EV_READ|EV_PERSIST,callback_accept,base);//注册事件,当client连接成功时,调用accept函数
   if(event==NULL)
   {
       perror("event_new error");
       event_base_free(base);
       return -3;
   }
   event_add(event,NULL);
   event_base_dispatch(base);
   event_base_free(base);
   event_free(event);

   evutil_closesocket(listenfd);//关闭套接字

   return 0;
}




































0 0
原创粉丝点击