Linux IO多路復(fù)用之epoll網(wǎng)絡(luò)編程
前言
本章節(jié)是用基本的Linux基本函數(shù)加上epoll調(diào)用編寫一個完整的服務(wù)器和客戶端例子,可在Linux上運行,客戶端和服務(wù)端的功能如下:
- 客戶端從標準輸入讀入一行,發(fā)送到服務(wù)端
- 服務(wù)端從網(wǎng)絡(luò)讀取一行,然后輸出到客戶端
- 客戶端收到服務(wù)端的響應(yīng),輸出這一行到標準輸出
服務(wù)端
代碼如下:
#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]; /* 設(shè)置每個進程允許打開的最大文件數(shù) */ 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; } /* 創(chuàng)建 epoll 句柄,把監(jiān)聽 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 (;;) { /* 等待有事件發(fā)生 */ 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);//響應(yīng)客戶端 return 0; }
編譯
編譯和啟動服務(wù)端
gcc epollserver.c -o epollserver ./epollserver
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
樹莓派無線上網(wǎng)時無屏幕下發(fā)現(xiàn)樹莓派IP的方法
今天小編就為大家分享一篇關(guān)于樹莓派無線上網(wǎng)時無屏幕下發(fā)現(xiàn)樹莓派IP的方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-04-04開發(fā)、運維不可不看的Linux調(diào)測工具【推薦】
這篇文章主要介紹了開發(fā)、運維不可不看的Linux調(diào)測工具,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-06-06如何在Linux中route?add命令添加路由(Linux?route)
route?add命令是用于管理Linux操作系統(tǒng)網(wǎng)絡(luò)路由,允許用戶添加、刪除或修改網(wǎng)絡(luò)路由表中的條目,在Linux系統(tǒng)上添加靜態(tài)路由,靜態(tài)路由是手動配置的路由,它指定了數(shù)據(jù)包從一個網(wǎng)絡(luò)到達另一個網(wǎng)絡(luò)的路徑,通過添加靜態(tài)路由,可實現(xiàn)網(wǎng)絡(luò)分段、轉(zhuǎn)發(fā)和通信等2024-06-06用DNSPod和Squid打造自己的CDN (五) 安裝Squid的前期準備
從本章開始,大家將會學(xué)到如何在Linux下面安裝、編譯程序,還會學(xué)到程序編譯的優(yōu)化方法,最后會通過源代碼編譯的方式把Squid安裝上2013-04-04Ubuntu Server 11.10安裝配置lamp(Apache+MySQL+PHP)
這篇文章主要介紹了Ubuntu Server 11.10安裝配置lamp(Apache+MySQL+PHP),需要的朋友可以參考下2016-10-10