libevent實現tcp伺服器
阿新 • • 發佈:2022-03-08
伺服器端 libevent 建立TCP連線:
- 建立event_base
- 建立bufferevent事件物件。bufferevent_socket_new();
- 使用bufferevent_setcb() 函式給 bufferevent的 read、write、event 設定回撥函式。
- 當監聽的 事件滿足時,read_cb會被呼叫, 在其內部 bufferevent_read();讀
- 使用 evconnlistener_new_bind 建立監聽伺服器, 設定其回撥函式,當有客戶端成功連線時,這個回撥函式會被呼叫。
- 封裝 listner_cb() 在函式內部。完成與客戶端通訊。
- 設定讀緩衝、寫緩衝的 使能狀態 enable、disable
- 啟動迴圈 event_base_dispath();
- 釋放連線。
程式碼
server.c
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <event2/event.h> #include <event2/listener.h> #include <event2/bufferevent.h> // 讀緩衝區回撥 void read_cb(struct bufferevent *bev, void *arg) { char buf[1024] = {0}; bufferevent_read(bev, buf, sizeof(buf)); printf("client say: %s\n", buf); char *p = "我是伺服器, 已經成功收到你傳送的資料!"; // 發資料給客戶端 bufferevent_write(bev, p, strlen(p)+1); sleep(1); } // 寫緩衝區回撥 void write_cb(struct bufferevent *bev, void *arg) { printf("I'm伺服器, 成功寫資料給客戶端,寫緩衝區回撥函式被回撥...\n"); } // 事件 void event_cb(struct 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"); } bufferevent_free(bev); printf("buffevent 資源已經被釋放...\n"); } void cb_listener( struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *addr, int len, void *ptr) { printf("connect new client\n"); struct event_base* base = (struct event_base*)ptr; // 通訊操作 // 新增新事件 struct bufferevent *bev; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); // 給bufferevent緩衝區設定回撥 bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL); bufferevent_enable(bev, EV_READ); } int main(int argc, const char* argv[]) { // init server struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_port = htons(9876); serv.sin_addr.s_addr = htonl(INADDR_ANY); struct event_base* base; base = event_base_new(); // 建立套接字 // 繫結 // 接收連線請求 struct evconnlistener* listener; listener = evconnlistener_new_bind(base, cb_listener, base, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 36, (struct sockaddr*)&serv, sizeof(serv)); event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); return 0; }
client.c
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <event2/bufferevent.h> #include <event2/event.h> #include <arpa/inet.h> void read_cb(struct bufferevent *bev, void *arg) { char buf[1024] = {0}; bufferevent_read(bev, buf, sizeof(buf)); printf("fwq say:%s\n", buf); bufferevent_write(bev, buf, strlen(buf)+1); sleep(1); } void write_cb(struct bufferevent *bev, void *arg) { printf("----------我是客戶端的寫回調函式,沒卵用\n"); } void event_cb(struct 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"); } else if(events & BEV_EVENT_CONNECTED) { printf("已經連線伺服器...\\(^o^)/...\n"); return; } // 釋放資源 bufferevent_free(bev); } // 客戶端與使用者互動,從終端讀取資料寫給伺服器 void read_terminal(evutil_socket_t fd, short what, void *arg) { // 讀資料 char buf[1024] = {0}; int len = read(fd, buf, sizeof(buf)); struct bufferevent* bev = (struct bufferevent*)arg; // 傳送資料 bufferevent_write(bev, buf, len+1); } int main(int argc, const char* argv[]) { struct event_base* base = NULL; base = event_base_new(); int fd = socket(AF_INET, SOCK_STREAM, 0); // 通訊的fd放到bufferevent中 struct bufferevent* bev = NULL; bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); // init server info struct sockaddr_in serv; memset(&serv, 0, sizeof(serv)); serv.sin_family = AF_INET; serv.sin_port = htons(9876); inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr); // 連線伺服器 bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv)); // 設定回撥 bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL); // 設定讀回撥生效 // bufferevent_enable(bev, EV_READ); // 建立事件, 這個是和使用者介面建立互動 struct event* ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, read_terminal, bev); // 新增事件 event_add(ev, NULL); event_base_dispatch(base); event_free(ev); event_base_free(base); return 0; }