Linux IO多路复用之epoll网络编程
吾爱主题
阅读:157
2024-04-05 13:56:17
评论:0
前言
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:
- 客户端从标准输入读入一行,发送到服务端
- 服务端从网络读取一行,然后输出到客户端
- 客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | #include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <sys/epoll.h> /* epoll function */ #include <fcntl.h> /* nonblocking */ #include <sys/resource.h> /*setrlimit */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MAXEPOLLSIZE 10000 #define MAXLINE 10240 int handle( int connfd); int setnonblocking( int sockfd) { if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) { return -1; } return 0; } int main( int argc, char **argv) { int servPort = 6888; int listenq = 1024; int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = 0; struct sockaddr_in servaddr, cliaddr; socklen_t socklen = sizeof ( struct sockaddr_in); struct epoll_event ev; struct epoll_event events[MAXEPOLLSIZE]; struct rlimit rt; char buf[MAXLINE]; /* 设置每个进程允许打开的最大文件数 */ rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE; if (setrlimit(RLIMIT_NOFILE, &rt) == -1) { perror ( "setrlimit error" ); return -1; } bzero(&servaddr, sizeof (servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl (INADDR_ANY); servaddr.sin_port = htons (servPort); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd == -1) { perror ( "can't create socket file" ); return -1; } int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)); if (setnonblocking(listenfd) < 0) { perror ( "setnonblock error" ); } if (bind(listenfd, ( struct sockaddr *) &servaddr, sizeof ( struct sockaddr)) == -1) { perror ( "bind error" ); return -1; } if (listen(listenfd, listenq) == -1) { perror ( "listen error" ); return -1; } /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */ kdpfd = epoll_create(MAXEPOLLSIZE); ev.events = EPOLLIN | EPOLLET; ev.data.fd = listenfd; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0) { fprintf (stderr, "epoll set insertion error: fd=%d\n" , listenfd); return -1; } curfds = 1; printf ( "epollserver startup,port %d, max connection is %d, backlog is %d\n" , servPort, MAXEPOLLSIZE, listenq); for (;;) { /* 等待有事件发生 */ nfds = epoll_wait(kdpfd, events, curfds, -1); if (nfds == -1) { perror ( "epoll_wait" ); continue ; } /* 处理所有事件 */ for (n = 0; n < nfds; ++n) { if (events[n].data.fd == listenfd) { connfd = accept(listenfd, ( struct sockaddr *)&cliaddr,&socklen); if (connfd < 0) { perror ( "accept error" ); continue ; } sprintf (buf, "accept form %s:%d\n" , inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); printf ( "%d:%s" , ++acceptCount, buf); if (curfds >= MAXEPOLLSIZE) { fprintf (stderr, "too many connection, more than %d\n" , MAXEPOLLSIZE); close(connfd); continue ; } if (setnonblocking(connfd) < 0) { perror ( "setnonblocking error" ); } ev.events = EPOLLIN | EPOLLET; ev.data.fd = connfd; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0) { fprintf (stderr, "add socket '%d' to epoll failed: %s\n" , connfd, strerror ( errno )); return -1; } curfds++; continue ; } // 处理客户端请求 if (handle(events[n].data.fd) < 0) { epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev); curfds--; } } } close(listenfd); return 0; } int handle( int connfd) { int nread; char buf[MAXLINE]; nread = read(connfd, buf, MAXLINE); //读取客户端socket流 if (nread == 0) { printf ( "client close the connection\n" ); close(connfd); return -1; } if (nread < 0) { perror ( "read error" ); close(connfd); return -1; } write(connfd, buf, nread); //响应客户端 return 0; } |
编译
编译和启动服务端
?1 2 | gcc epollserver.c -o epollserver ./epollserver |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。如果你想了解更多相关内容请查看下面相关链接
原文链接:https://blog.csdn.net/woniu211111/article/details/47318843
声明
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。