epoll 边沿触发 非阻塞 IO 服务器
生活随笔
收集整理的這篇文章主要介紹了
epoll 边沿触发 非阻塞 IO 服务器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在之前的文章中提到過Readn 函數:
ssize_t Readn(int fd, void *vptr, size_t n)試想這樣一種情況:
1、server 循環使用 epoll_wait,監聽 fd,fd 發生讀事件,epoll_wait 通知 server。
2、server 接到通知,調用 Readn 函數,讀取 500 字節。
3、但是,client 就發送了 200 字節,不足 500 字節。
4、此時,server 會阻塞在 Readn 函數上。
5、意味著 server 無法執行下一次 epoll_wait,意味著即使 client 再給 server 發數據,server 也得不到通知。
6、server 得不到通知,就無法讀數據,就無法解除 Readn 函數的阻塞。
結果:造成“死鎖”現象。
解決:將“套接字的文件描述符”設置為非阻塞 。
epoll的“邊沿模式”下的“非阻塞讀”模型
#include <stdio.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/epoll.h> #include <unistd.h> #include <fcntl.h> #define MAXLINE 10 #define SERV_PORT 8000 int main(void) {struct sockaddr_in servaddr;socklen_t cliaddr_len;int listenfd, connfd;char buf[MAXLINE];char str[INET_ADDRSTRLEN];int efd, flag;listenfd = socket(AF_INET, SOCK_STREAM, 0); // 創建套接字bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); // 綁定端口和IPlisten(listenfd, 20); // 設置同時訪問上限數struct epoll_event event; // epoll_ctl 傳入參數struct epoll_event resevent[10]; // epoll_wait 傳出參數int res, len;efd = epoll_create(10); // 創建epoll樹根event.events = EPOLLIN | EPOLLET; /* ET 邊沿觸發,默認是水平觸發 */printf("Accepting connections ...\n");truct sockaddr_in cliaddr;cliaddr_len = sizeof(cliaddr);connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); // 阻塞等待連接,獲得connfdprintf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port)); // 獲得客戶端信息flag = fcntl(connfd, F_GETFL); /* 修改connfd為非阻塞讀 */ // connfd 設置為非阻塞flag |= O_NONBLOCK;fcntl(connfd, F_SETFL, flag);event.data.fd = connfd; // 至此epoll_ctl 傳入參數設置完畢epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &event); // 將connfd加入監聽紅黑樹while (1) {printf("epoll_wait begin\n");res = epoll_wait(efd, resevent, 10, -1); // 最多10個, 阻塞監聽printf("epoll_wait end res %d\n", res);if (resevent[0].data.fd == connfd) {while ((len = read(connfd, buf, MAXLINE / 2)) > 0) write(STDOUT_FILENO, buf, len); }}return 0; } // 如果是 非阻塞,邊沿觸發:read 不會阻塞,wait 只調用 1 次,while 循環 2 次 // 如果是 非阻塞,水平觸發:read 不會阻塞,wait 需調用 2 次,while 循環 2 次總結
以上是生活随笔為你收集整理的epoll 边沿触发 非阻塞 IO 服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: epoll 边沿触发(ET 模式)和水平
- 下一篇: epoll反应堆