Libevent例子(一)

服务器端

#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 = (struct 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;
}

客户端

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值