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