Installation under Linux Libevent simple and practical

Foreword

Libevent is a C language, lightweight, open source library of high-performance event notification, mainly in the following highlights: event-driven (event-driven), high performance; lightweight, focused on the network, as so bloated ACE huge; source code is quite refined, easy to read; cross-platform support for Windows, Linux, * BSD and Mac Os; support a variety of I / O multiplexing, epoll, poll, dev / poll, select and kqueue etc; support I / O, timers and signal events such as; registration event priority. Libevent has been widely applied, as the underlying network database; such memcached, Vomit, Nylon, Netchat etc.

Download and install Libevent

1. Download
the official website: http://libevent.org/ , the latest version is 2.1
Download compressed package named 2.1.11-stable.tar.gz-libevent
2. unzip

tar -zxvf libevent-2.1.11-stable.tar.gz 

Installation Path Configuration

cd libevent-2.1.11-stable
./configure

You can also specify a suffix, such as path./configure -prefix=/usr

4. compile and install

make
make install

5. Test whether the installed

ls -al /usr/local/lib | grep libevent

6. Use a sample program to test

cd sample/

Under this directory, there are many examples, can be tested, you can also learn

Use Libevent to write simple programs and compile

Use libevent library development programs, the default compiler need to add -levent
question : If it is found at compile or run time appears: error while loading shared libraries: libevent -2.1.so.7: can not open shared object file: No such file or directory
you want to see whether libevent-2.1.so.7 exist, you need to install mlocate

locate libevent-2.1.so.7

Results: The system has been installed the module, in the path / usr / local / lib /
mapped to the libevent-2.1.so.7 to lib64

ln -s /usr/local/lib/libevent-2.1.so.7 /usr/lib64/libevent-2.1.so.7

Then you can run a normal

Libevent program example

Elementary

Client code

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<event.h>
#include<event2/util.h>

int tcp_connect_server(const char* server_ip, int port);
void cmd_msg_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg);
 
int main(int argc, char** argv)
{
    if( argc < 3 )
    {
        printf("please input 2 parameter\n");
        return -1;
    }
    //两个参数依次是服务器端的IP地址、端口号
    int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
    if( sockfd == -1)
    {
        perror("tcp_connect error ");
        return -1;
    }
    printf("connect to server successful\n");
    struct event_base* base = event_base_new();
    struct event *ev_sockfd = event_new(base, sockfd,
                                        EV_READ | EV_PERSIST,
                                        socket_read_cb, NULL);
    event_add(ev_sockfd, NULL);
    //监听终端输入事件
    struct event* ev_cmd = event_new(base, STDIN_FILENO,
                                      EV_READ | EV_PERSIST, cmd_msg_cb,
                                      (void*)&sockfd);
    event_add(ev_cmd, NULL);
    event_base_dispatch(base);
    printf("finished \n");
    return 0;
}

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[1024];
    //为了简单起见,不考虑读一半数据的情况
    int len = read(fd, msg, sizeof(msg)-1);
    if( len <= 0 )
    {
        perror("read fail ");
        exit(1);
    }
    msg[len] = '\0';
    printf("recv %s from server\n", msg);
}

typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{
    int sockfd, status, save_errno;
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    status = inet_aton(server_ip, &server_addr.sin_addr);
    if( status == 0 ) //the server_ip is not valid value
    {
        errno = EINVAL;
        return -1;
    }
    sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
    if( sockfd == -1 )
        return sockfd;
    status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );
   
    if( status == -1 )
    {
        save_errno = errno;
        ::close(sockfd);
        errno = save_errno; //the close may be error
        return -1;
    }
    evutil_make_socket_nonblocking(sockfd);
    return sockfd;
}

Server code

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>
#include<event.h>

void accept_cb(int fd, short events, void* arg);
void socket_read_cb(int fd, short events, void *arg);
int tcp_server_init(int port, int listen_num);
 
int main(int argc, char** argv)
{
    int listener = tcp_server_init(9999, 10);
    if( listener == -1 )
    {
        perror(" tcp_server_init error ");
        return -1;
    }
    struct event_base* base = event_base_new();
    //添加监听客户端请求连接事件
    struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
                                        accept_cb, base);
    event_add(ev_listen, NULL);
    event_base_dispatch(base);
    return 0;
}

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;
    //仅仅是为了动态创建一个event结构体
    struct event *ev = event_new(NULL, -1, 0, NULL, NULL);
    //将动态创建的结构体作为event的回调参数
    event_assign(ev, base, sockfd, EV_READ | EV_PERSIST,
                 socket_read_cb, (void*)ev);
    event_add(ev, NULL);
}

void socket_read_cb(int fd, short events, void *arg)
{
    char msg[4096];
    struct event *ev = (struct event*)arg;
    int len = read(fd, msg, sizeof(msg) - 1);
    if( len <= 0 )
    {
        printf("some error happen when read\n");
        event_free(ev);
        close(fd);
        return ;
    }
    msg[len] = '\0';
    printf("recv the client msg: %s", msg);
    char reply_msg[4096] = "I have recvieced the msg: ";
    strcat(reply_msg + strlen(reply_msg), msg);
    write(fd, reply_msg, strlen(reply_msg) );
}

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;
}

medium

Client code

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h>
 
int tcp_connect_server(const char* server_ip, int port);
void cmd_msg_cb(int fd, short events, void* arg);
void server_msg_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
 
int main(int argc, char** argv)
{
    if( argc < 3 )
    {
        printf("please input 2 parameter\n");
        return -1;
    }
    //两个参数依次是服务器端的IP地址、端口号
    int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));
    if( sockfd == -1)
    {
        perror("tcp_connect error ");
        return -1;
    }
    printf("connect to server successful\n");
    struct event_base* base = event_base_new();
    struct bufferevent* bev = bufferevent_socket_new(base, sockfd,
                                                     BEV_OPT_CLOSE_ON_FREE);
    //监听终端输入事件
    struct event* ev_cmd = event_new(base, STDIN_FILENO,
                                      EV_READ | EV_PERSIST, cmd_msg_cb,
                                      (void*)bev);
    event_add(ev_cmd, NULL);
    //当socket关闭时会用到回调参数
    bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);
    event_base_dispatch(base);
    printf("finished \n");
    return 0;
}

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);
    }
    struct bufferevent* bev = (struct bufferevent*)arg;
    //把终端的消息发送给服务器端
    bufferevent_write(bev, msg, ret);
}

void server_msg_cb(struct bufferevent* bev, void* arg)
{
    char msg[1024];
    size_t len = bufferevent_read(bev, msg, sizeof(msg));
    msg[len] = '\0';
    printf("recv %s from server\n", msg);
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
    if (event & BEV_EVENT_EOF)
        printf("connection closed\n");
    else if (event & BEV_EVENT_ERROR)
        printf("some other error\n");
    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
    struct event *ev = (struct event*)arg;
    //因为socket已经没有,所以这个event也没有存在的必要了
    event_free(ev);
}

typedef struct sockaddr SA;
int tcp_connect_server(const char* server_ip, int port)
{
    int sockfd, status, save_errno;
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    status = inet_aton(server_ip, &server_addr.sin_addr);
    if( status == 0 ) //the server_ip is not valid value
    {
        errno = EINVAL;
        return -1;
    }
    sockfd = ::socket(PF_INET, SOCK_STREAM, 0);
    if( sockfd == -1 )
        return sockfd;
    status = ::connect(sockfd, (SA*)&server_addr, sizeof(server_addr) );
    if( status == -1 )
    {
        save_errno = errno;
        ::close(sockfd);
        errno = save_errno; //the close may be error
        return -1;
    }
    evutil_make_socket_nonblocking(sockfd);
    return sockfd;
}

Server code

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<event.h>
#include<event2/bufferevent.h>

void accept_cb(int fd, short events, void* arg);
void socket_read_cb(bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);
int tcp_server_init(int port, int listen_num);
 
int main(int argc, char** argv)
{
    int listener = tcp_server_init(9999, 10);
    if( listener == -1 )
    {
        perror(" tcp_server_init error ");
        return -1;
    }
    struct event_base* base = event_base_new();
    //添加监听客户端请求连接事件
    struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,
                                        accept_cb, base);
    event_add(ev_listen, NULL);
    event_base_dispatch(base);
    event_base_free(base);
    return 0;
}

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;
    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 | EV_PERSIST);
}

void socket_read_cb(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", msg);
    char reply_msg[4096] = "I have recvieced the msg: ";
    strcat(reply_msg + strlen(reply_msg), msg);
    bufferevent_write(bev, reply_msg, strlen(reply_msg));
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
    if (event & BEV_EVENT_EOF)
        printf("connection closed\n");
    else if (event & BEV_EVENT_ERROR)
        printf("some other error\n");
    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
}

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;
}

higher

Client code

#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<unistd.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<event.h>
#include<event2/bufferevent.h>
#include<event2/buffer.h>
#include<event2/util.h>

int tcp_connect_server(const char* server_ip, int port);
void cmd_msg_cb(int fd, short events, void* arg);
void server_msg_cb(struct bufferevent* bev, void* arg);
void event_cb(struct bufferevent *bev, short event, void *arg);

int main(int argc, char** argv)
{
    if( argc < 3 )
    {
        //两个参数依次是服务器端的IP地址、端口号
        printf("please input 2 parameter\n");
        return -1;
    }
    struct event_base *base = event_base_new();
    struct bufferevent* bev = bufferevent_socket_new(base, -1,
                                                     BEV_OPT_CLOSE_ON_FREE);
    //监听终端输入事件
    struct event* ev_cmd = event_new(base, STDIN_FILENO,
                                     EV_READ | EV_PERSIST,
                                     cmd_msg_cb, (void*)bev);
    event_add(ev_cmd, NULL);
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(argv[2]));
    inet_aton(argv[1], &server_addr.sin_addr);
    bufferevent_socket_connect(bev, (struct sockaddr *)&server_addr,
                               sizeof(server_addr));
    bufferevent_setcb(bev, server_msg_cb, NULL, event_cb, (void*)ev_cmd);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);
    event_base_dispatch(base);
    printf("finished \n");
    return 0;
}

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);
    }
    struct bufferevent* bev = (struct bufferevent*)arg;
    //把终端的消息发送给服务器端
    bufferevent_write(bev, msg, ret);
}

void server_msg_cb(struct bufferevent* bev, void* arg)
{
    char msg[1024];
    size_t len = bufferevent_read(bev, msg, sizeof(msg));
    msg[len] = '\0';
    printf("recv %s from server\n", msg);
}

void event_cb(struct bufferevent *bev, short event, void *arg)
{
    if (event & BEV_EVENT_EOF)
        printf("connection closed\n");
    else if (event & BEV_EVENT_ERROR)
        printf("some other error\n");
    else if( event & BEV_EVENT_CONNECTED)
    {
        printf("the client has connected to server\n");
        return ;
    }
    //这将自动close套接字和free读写缓冲区
    bufferevent_free(bev);
    struct event *ev = (struct event*)arg;
    event_free(ev);
}

Server code

#include<netinet/in.h>  
#include<sys/socket.h>  
#include<unistd.h>  
#include<stdio.h>  
#include<string.h>  
#include<event.h>  
#include<listener.h>  
#include<bufferevent.h>  
#include<thread.h>  

void listener_cb(evconnlistener *listener, evutil_socket_t fd,  
                 struct sockaddr *sock, int socklen, void *arg);  
void socket_read_cb(bufferevent *bev, void *arg);  
void socket_event_cb(bufferevent *bev, short events, void *arg);  
  
int main()  
{  
    //evthread_use_pthreads();//enable threads  
    struct sockaddr_in sin;  
    memset(&sin, 0, sizeof(struct sockaddr_in));  
    sin.sin_family = AF_INET;  
    sin.sin_port = htons(9999);  
    event_base *base = event_base_new();  
    evconnlistener *listener  
            = evconnlistener_new_bind(base, listener_cb, base,  
                                      LEV_OPT_REUSEABLE|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;  
}  

//一个新客户端连接上服务器了  
//当此函数被调用时,libevent已经帮我们accept了这个客户端。该客户端的
//文件描述符为fd
void listener_cb(evconnlistener *listener, evutil_socket_t fd,  
                 struct sockaddr *sock, int socklen, void *arg)  
{  
    printf("accept a client %d\n", fd);  
    event_base *base = (event_base*)arg;  
    //为这个客户端分配一个bufferevent  
    bufferevent *bev =  bufferevent_socket_new(base, fd,  
                                               BEV_OPT_CLOSE_ON_FREE);  
    bufferevent_setcb(bev, socket_read_cb, NULL, socket_event_cb, NULL);  
    bufferevent_enable(bev, EV_READ | EV_PERSIST);  
}  

void socket_read_cb(bufferevent *bev, void *arg)  
{  
    char msg[4096];  
    size_t len = bufferevent_read(bev, msg, sizeof(msg)-1 );  
    msg[len] = '\0';  
    printf("server read the data %s\n", msg);  
    char reply[] = "I has read your data";  
    bufferevent_write(bev, reply, strlen(reply) );  
}  

void socket_event_cb(bufferevent *bev, short events, void *arg)  
{  
    if (events & BEV_EVENT_EOF)  
        printf("connection closed\n");  
    else if (events & BEV_EVENT_ERROR)  
        printf("some other error\n");  
    //这将自动close套接字和free读写缓冲区  
    bufferevent_free(bev);  
}  

Some questions about when libevent program can read "libevent Programming Troubleshooting." If readers would like to know the specific implementation libevent, read "libevent source code analysis" system article.

More Articles Reference:
http://blog.csdn.net/luotuo44/article/details/39547391
HTTPS: /blog.csdn.net/luotuo44/article/category/2435521

Guess you like

Origin www.cnblogs.com/WindSun/p/12142656.html