libev+TCP伺服器事件輪詢例項demo
阿新 • • 發佈:2018-12-21
概述:
使用libev實現TCP伺服器,提升處理效率。原理其實都一樣,都是檔案描述符,檢查讀寫條件,使用epoll事件輪詢機制。
例項Demo:
#include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <stdint.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <ev.h> #define PORT 12100 #define BUFFER_SIZE 1024 #define MAX_LISTEN 5 /*初始化服務端*/ int server_socket_init(int *sd, char *ipaddr, uint16_t port) { //建立socket int sock = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sock) goto err1; //設定立即釋放埠並可以再次使用 int reuse = 1; if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) goto err2; //設定為非阻塞 if (-1 == fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK)) goto err2; struct sockaddr_in addr; memset(&addr, 0 , sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (NULL == ipaddr) { addr.sin_addr.s_addr = htonl(INADDR_ANY); } else { addr.sin_addr.s_addr = inet_addr(ipaddr); } //繫結監聽 if (-1 == bind(sock, (struct sockaddr *)&addr, sizeof(addr))) goto err2; if (-1 == listen(sock, MAX_LISTEN)) goto err2; *sd = sock; return 0; err2: close(sock); err1: return -1; } /*讀回撥*/ void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { char buffer[BUFFER_SIZE] = {0}; if (EV_ERROR & revents) { printf("read got invalid event...\r\n"); return; } int res = 0; int32_t bytes = read(watcher->fd, buffer, sizeof(buffer)); if (-1 == bytes) { //tcp Error if (EINTR != errno && EAGAIN != errno) { res = 1; } } else if (0 == bytes) { //tcp Close res = 2; } if (0 != res) { //關閉事件迴圈並釋放watcher printf("TCP CLOSE\r\n"); ev_io_stop(loop,watcher); free(watcher); } else { printf("READ:\r\n %s\r\n", buffer); } } /*accept回撥函式*/ void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { struct sockaddr_in client_addr; socklen_t client_len = sizeof(client_addr); if (EV_ERROR & revents) { printf("accept got invalid event...\r\n"); return; } //accept連線 int sock = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len); if (-1 == sock) { return; } //設定非阻塞 if(-1 == fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK)) { close(sock); return; } printf("Successfully connected with client: %s:%u\r\n", \ inet_ntoa(client_addr.sin_addr), client_addr.sin_port); //加入事件迴圈 struct ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io)); ev_io_init(w_client, read_cb, sock, EV_READ); ev_io_start(loop, w_client); } int main() { int sd; struct ev_io w_accept; struct ev_loop *loop = ev_loop_new(EVBACKEND_EPOLL); if (NULL == loop) { printf("loop create failed\r\n"); return -1; } if (server_socket_init(&sd, NULL, PORT) < 0) { printf("server init failed\r\n"); return -1; } ev_io_init(&w_accept, accept_cb, sd, EV_READ); ev_io_start(loop, &w_accept); ev_run(loop, 0); return 0; }
編譯:
//編譯
gcc -o ev_server ev_server.c -lev