Libevent使用例子,從簡單到復雜
阿新 • • 發佈:2017-06-29
enable targe 描述 har ron 請求 got memset repl
轉載請註明出處:http://blog.csdn.net/luotuo44/article/details/39670221
本文從簡單到復雜,展示如何使用libevent。網上的許多例子都是只有服務器端的,本文裏面客戶端和服務器端都有,以饗讀者。
關於libevent編程時的一些疑問可以閱讀《libevent編程疑難解答》。假如讀者還想了解libevent的具體實現,可以閱讀《libevent源碼分析》系統文章。
不說這麽多了,直接上代碼。
初等:
客戶端代碼:
#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> inttcp_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; }
服務器端代碼:
#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; }
中等:
客戶端代碼:
#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; }
服務器端代碼:
#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; }
高等:
客戶端代碼:
#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); }
服務器端代碼:
#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); }
http://blog.csdn.net/luotuo44/article/details/39670221
Libevent使用例子,從簡單到復雜