zoukankan      html  css  js  c++  java
  • 使用bufferevent进行libevent服务端和客户端的开发

    参考了网上的一些例子,实验了基于bufferevent的开发。

    首先是服务端:

    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <unistd.h>
    
    #include <stdio.h>
    #include <string.h>
    
    #include <event.h>
    #include <event2/listener.h>
    #include <event2/bufferevent.h>
    #include <event2/thread.h>
    
    using namespace std;
    
    void listener_cb(evconnlistener *listener, evutil_socket_t fd,
             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(int argc, char **argv) {
    
        sockaddr_in sin;
        memset(&sin, 0, sizeof(sockaddr_in));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(8899);
    
        event_base *base = event_base_new();
        evconnlistener *listener
            = evconnlistener_new_bind(base,
                          listener_cb, base,
                          LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,
                          10, (sockaddr*)&sin, sizeof(sockaddr_in));
    
        event_base_dispatch(base);
    
        evconnlistener_free(listener);
        event_base_free(base);
    
    }
    
    void listener_cb(evconnlistener *listener, evutil_socket_t fd,
            sockaddr *sock, int socklen, void *arg) {
    
        printf("accept a client %d
    ", fd);
        event_base *base = (event_base *) arg;
    
        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] = '';
        printf("Server read the data: %s
    ", msg);
    
        char reply[] = "I have 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
    ");
        }
        else if (events & BEV_EVENT_ERROR) {
            printf("some other error
    ");
        }
    
        bufferevent_free(bev);
    }

    编译命令:

    g++ -o lserver lserver.cpp -I/usr/local/include -levent -L/usr/local/lib -Wl,-rpath=/usr/local/lib

    2016.09.28

    我把server和client编译的命令,整理成了新的Makefile文件:

    CXX=/opt/compiler/gcc-4.8.2/bin/g++
    
    INCPATH= 
            /home/work/.jumbo/include/
    
    DEP_LDFLAGS= 
            -L/home/work/.jumbo/lib/
    
    DEP_LDLIBS= 
            -levent 
            -lpthread
    
    TARGET= lserver lclient
    
    all : $(TARGET)
    
    lserver : lserver.cc
            $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
    
    lclient : lclient.cc
            $(CXX) -o $@ $^ -I$(INCPATH) $(DEP_LDFLAGS) $(DEP_LDLIBS)
    
    .PHONY : all clean
    
    clean :
            rm -rf $(TARGET)

    然后是客户端:

    #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(bufferevent *bev, void *arg);
    
    void event_cb(bufferevent *bev, short event, void *arg);
    
    int main(int argc, char **argv) {
        if (argc < 3) {
            printf("please input IP and port
    ");
            return 1;
        }
    
        event_base *base = event_base_new();
    
        bufferevent *bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
    
        event *ev_cmd = event_new(base, STDIN_FILENO,
                      EV_READ|EV_PERSIST,
                      cmd_msg_cb, (void *)bev);
    
        event_add(ev_cmd, NULL);
    
        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, (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
    ");
        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);
        }
    
        bufferevent *bev = (bufferevent *)arg;
        bufferevent_write(bev, msg, ret);
    }
    
    void server_msg_cb(bufferevent *bev, void *arg) {
        char msg[1024];
    
        size_t len = bufferevent_read(bev, msg, sizeof(msg)-1);
        msg[len] = '';
    
        printf("Recv %s from server.
    ", msg);
    }
    
    void event_cb(bufferevent *bev, short event, void *arg) {
        if (event & BEV_EVENT_EOF) {
            printf("Connection closed.
    ");
        }
        else if (event & BEV_EVENT_ERROR) {
            printf("Some other error.
    ");
        }
        else if (event & BEV_EVENT_CONNECTED) {
            printf("Client has successfully cliented.
    ");
            return;
        }
    
        bufferevent_free(bev);
    
        // free event_cmd
        // need struct as event is defined as parameter
        struct event *ev = (struct event *)arg;
        event_free(ev);
    }

    编译命令:

    g++ -o lclient lclient.cpp -I/usr/local/include -levent -L/usr/local/lib -Wl,-rpath=/usr/local/lib

    运行服务器命令:

    ./lserver

    运行客户端命令:

    ./lclient 127.0.0.1 8899

    多次交互之后的两边输出结果为:

    [server]$ ./lserver 
    accept a client 7
    Server read the data: aaa
    
    Server read the data: bbb
    
    Server read the data: ccc
    
    Server read the data: ddd
    
    Server read the data: eeeee
    [client]$ ./lclient 127.0.0.1 8899
    Client has successfully cliented.
    aaa
    Recv I have read your data. from server.
    bbb
    Recv I have read your data. from server.
    ccc
    Recv I have read your data. from server.
    ddd
    Recv I have read your data. from server.
    eeeee
    Recv I have read your data. from server.

    如果先关闭客户端(Ctrl-C,也就是SIGINT),服务器端会打印一条提示,但是仍然可以接受其他的请求。

    [server]$ ./lserver 
    accept a client 7
    Server read the data: aaa
    
    Server read the data: bbb
    
    Server read the data: ccc
    
    Server read the data: ddd
    
    Server read the data: eeeee
    
    connection closed
    accept a client 7
    Server read the data: ttt

    如果先关闭服务器端(Ctrl-C,也就是SIGINT),客户端也会关闭:

    [client]$ ./lclient 127.0.0.1 8899
    Client has successfully cliented.
    ttt
    Recv I have read your data. from server.
    Connection closed.
    Finished

    这是因为在客户端上关联的event,包括socket的event(通过bufferevent_free关闭),和cmd的event(通过event_free关闭),都已经被关闭了。那么整个event_base_dispatch的循环就返回了。

  • 相关阅读:
    PHPUnit
    变长参数处理
    springMVC课程笔记(二)springMVC组件配置
    URL编码以及GET和POST提交乱码解决方案
    springMVC课程笔记(一)springMVC架构原理分析
    ELK(ElasticSearch, Logstash, Kibana) 实现 Java 分布式系统日志分析架构
    Java 标准 IO 流编程一览笔录( 下 )
    Java 标准 IO 流编程一览笔录( 上 )
    Zookeeper系列(十四)Zookeeper的数据与存储
    Zookeeper系列(十三)Zookeeper的请求处理
  • 原文地址:https://www.cnblogs.com/charlesblc/p/5456128.html
Copyright © 2011-2022 走看看