libevent学习笔记---- 回显服务器 (1)

    xiaoxiao2026-03-19  8

    最近在学习libevent,顺便写了几个例子。按照Unix网络编程里的经典例子,从echo server开始。所谓echo server(回显服务器), 就是服务器将客户端发送过来的信息原封不动的发送回给客户端。 以下是结合libevent的初级回显服务器代码:

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <event2/event.h> #define MAX_BUF_SIZE 1024 int n_send(int fd, void *data, int len, int flag) { int nsent = 0; int nleft = len; void *ptr = data; while (nleft > 0) { if ((nsent = send(fd, ptr, nleft, flag)) <= 0) { if (errno == EINTR) { continue; } else if (errno == EAGAIN) { usleep(100); continue; } else { fprintf(stderr, "send() error: errno %d --- %s\r\n", errno, strerror(errno)); break; } nleft -= nsent; ptr += nsent; } return (len - nleft); } void do_read_cb(int fd, short events, void *arg) { char buf[MAX_BUF_SIZE]; struct event *ev = (struct event *)arg; int len = 0; again: len = recv(fd, buf, sizeof(buf) - 1, 0); if (len < 0) { if (errno == EINTR) { goto again; } fprintf(stderr, "some error happened while receiving data, errno: %d--- %s\r\n", errno, strerror(errno)); event_free(ev); close(fd); return; } else if (len == 0) { fprintf(stderr, "socket closed by peer, fd = %d...\r\n", fd); event_free(ev); close(fd); return; } n_send(fd, buf, len, 0); } void do_accept_cb(int fd, short events, void *arg) { evutil_socket_t sock; struct sockaddr_in client; socklen_t len = sizeof(client); sock = accept(fd, (struct sockaddr *)&client, &len); if (sock < 0) { fprintf(stderr, "accept() error: errno %d --- %s\r\n", errno, strerror(errno)); return; } evutil_make_socket_nonblocking(sock); printf("A new client connected from %s on port %d, socket %d\r\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), sock); struct event_base *base = (struct event_base *)arg; struct event *ev = event_new(NULL, -1, 0, NULL, NULL); event_assign(ev, base, sock, EV_READ | EV_PERSIST, do_read_cb, (void *)ev); event_add(ev, NULL); } int init_echo_server(int port) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { fprintf(stderr, "socket() error: errno %d --- %s\r\n", errno, strerror(errno)); return -1; } evutil_make_listen_socket_reuseable(sock); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(port); if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { fprintf(stderr, "bind() error: errno %d --- %s\r\n", errno, strerror(errno)); goto error; } if (listen(sock, 32) < 0) { fprintf(stderr, "listen() error: errno %d --- %s\r\n", errno, strerror(errno)); goto error; } struct event_base *base = event_base_new(); struct event *ev_listen = event_new(base, sock, EV_READ | EV_PERSIST, do_accept_cb, base); event_add(ev_listen, NULL); event_base_dispatch(base); event_base_free(base); return 0; error: close(sock); return -1; } int main(int argc, char **argv) { int port = 9999; if (argc >= 2) { port = atoi(argv[1]); if (port < 0 || port > 65535) { fprintf(stderr, "Invalid port ...\r\n"); return -1; } } init_echo_server(port); return 0; }

    至于客户端代码,大家可以参考Unix网络编程。下面给出一个示例: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <ctype.h> #include <fcntl.h> #include <signal.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <arpa/inet.h> #include <netinet/in.h> #include <errno.h> #include <event.h> #include <event2/event.h> #include <event2/bufferevent.h> #include <event2/buffer.h> #include <event2/util.h> #include <event2/listener.h> int is_valid_ip_addr(const char *ip) { if (ip == NULL || strlen(ip) < 7) { return -1; } int len = strlen(ip); const char *start = ip; const char *end = ip + len - 1; int ret = 0; int dot_count = 0; int cur_val = 0; int val = -1; while (end > start && isspace(*end)) { --end; } while (start < end && isspace(*start)) { ++start; } if (start >= end || isdigit(*start) == 0 || isdigit(*end) == 0) { return -1; } while (start <= end) { while (start <= end && '0' <= *start && *start <= '9') { cur_val = 10 * cur_val + (*start - '0'); if (cur_val < 0 || cur_val > 255) { ret = -1; break; } val = cur_val; ++start; } if (start <= end) { if (*start == '.' && val != -1) { ++start; ++dot_count; cur_val = 0; val = -1; } else { ret = -1; break; } } else { break; } } if (ret == 0 && dot_count != 3) { ret = -1; } return ret; } int connect_with_timeout(int sock, struct sockaddr *sa, socklen_t sa_len, int seconds) { int flags, n, error; socklen_t len; fd_set rset, wset; struct timeval tv; flags = fcntl(sock, F_GETFL, 0); if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) { fprintf(stderr, "fcntl() error while set socket nonblocking: %d --- %s\r\n", errno, strerror(errno)); close(sock); return -1; } error = 0; if ((n = connect(sock, sa, sa_len)) < 0) { if (errno != EINPROGRESS) { fprintf(stderr, "connect() error: %d --- %s\r\n", errno, strerror(errno)); close(sock); return -1; } } if (n == 0) { goto done; } if (seconds <= 1) { seconds = 1; } FD_ZERO(&rset); FD_SET(sock, &rset); wset = rset; tv.tv_sec = seconds; tv.tv_usec = 0; if ((n = select(sock + 1, &rset, &wset, NULL, &tv)) == 0) { close(sock); fprintf(stderr, "connect to server timeout ...\r\n"); return -1; } if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) { len = sizeof(error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { close(sock); return -1; } } else { fprintf(stderr, "select() error: fd is not set\r\n"); close(sock); return -1; } done: if (fcntl(sock, F_SETFL, flags) < 0) { fprintf(stderr, "fcntl() error while set flags back: %d --- %s\r\n", error, strerror(errno)); close(sock); return -1; } if (error) { close(sock); errno = error; return -1; } return sock; } int create_tcp_connect_socket(char *ip_str, int port, int timeout) { int sock; struct sockaddr_in server_addr; uint32_t ip; if (ip_str == NULL || is_valid_ip_addr(ip_str) != 0) { printf("Invalid ip address ...\r\n"); return -1; } if (port < 0 || port > 65535) { printf("Invalid port number ...\r\n"); return -1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr(ip_str); if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "socket() error: %d --- %s\r\n", errno, strerror(errno)); return -1; } return connect_with_timeout(sock, (struct sockaddr *)&server_addr, sizeof(server_addr), timeout); } #define MAX_BUF_SIZE 1024 void do_read_cb(int fd, short events, void *arg) { char buf[MAX_BUF_SIZE]; int n; again: n = recv(fd, buf, sizeof(buf) - 1, 0); if (n < 0) { if (errno == EINTR) { goto again; } fprintf(stderr, "recv() error: errno %d --- %s\r\n", errno, strerror(errno)); return; } else if (n == 0) { printf("connection closed by peer.\r\n"); return; } buf[n] = '\0'; printf("%s", buf); } int n_send(int fd, void *data, int len, int flag) { int nsent = 0; int nleft = len; void *ptr = data; while (nleft > 0) { if ((nsent = send(fd, ptr, nleft, flag)) <= 0) { if (errno == EINTR) { continue; } else if (errno == EAGAIN) { usleep(100); continue; } else { fprintf(stderr, "send() error: errno %d --- %s\r\n", errno, strerror(errno)); break; } } nleft -= nsent; ptr += nsent; } return (len - nleft); } void console_read_cb(int fd, short events, void *arg) { char buf[MAX_BUF_SIZE]; int len = read(fd, buf, sizeof(buf)); if (len <= 0) { fprintf(stderr, "read() error: errno %d --- %s\r\n", errno, strerror(errno)); return; } int sock = (*(int *)arg); n_send(sock, buf, len, 0); } int main(int argc, char **argv) { if (argc < 3) { printf("usage: %s <ip> <port>\r\n", argv[0]); return -1; } int sock = create_tcp_connect_socket(argv[1], atoi(argv[2]), 3); if (sock < 0) { printf("cregate connect socket failed ...\r\n"); return -1; } evutil_make_socket_nonblocking(sock); struct event_base *base = event_base_new(); struct event *ev_sock = event_new(base, sock, EV_READ | EV_PERSIST, do_read_cb, base); event_add(ev_sock, NULL); struct event *ev_console = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, console_read_cb, (void *)&sock); event_add(ev_console, NULL); event_base_dispatch(base); event_base_free(base); return 0; }

    转载请注明原文地址: https://ju.6miu.com/read-1308127.html
    最新回复(0)