標籤:poll 高效tcp並發伺服器
想詳細徹底地瞭解poll或看懂下面的代碼請參考《Linux網路編程——I/O複用之poll函數》
代碼:
#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/select.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <poll.h>#include <errno.h>#define OPEN_MAX 100int main(int argc, char *argv[]){//1.建立tcp監聽通訊端int sockfd = socket(AF_INET, SOCK_STREAM, 0);//2.綁定sockfdstruct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr));my_addr.sin_family = AF_INET;my_addr.sin_port = htons(8000);my_addr.sin_addr.s_addr = htonl(INADDR_ANY);bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));//3.監聽listenlisten(sockfd, 10);//4.poll相應參數準備struct pollfd client[OPEN_MAX];int i = 0, maxi = 0;for(;i<OPEN_MAX; i++)client[i].fd = -1;//初始化poll結構中的檔案描述符fdclient[0].fd = sockfd;//需要監測的描述符client[0].events = POLLIN;//普通或優先順序帶資料可讀//5.對已串連的用戶端的資料處理while(1){int ret = poll(client, maxi+1, -1);//對加入poll結構體數組所有元素進行監測//5.1監測sockfd(監聽通訊端)是否存在串連if((client[0].revents & POLLIN) == POLLIN ){struct sockaddr_in cli_addr;int clilen = sizeof(cli_addr);int connfd = 0;//5.1.1 從tcp完成串連中提取用戶端connfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);//5.1.2 將提取到的connfd放入poll結構體數組中,以便於poll函數監測for(i=1; i<OPEN_MAX; i++){if(client[i].fd < 0){client[i].fd = connfd;client[i].events = POLLIN;break;}}//5.1.3 maxi更新if(i > maxi)maxi = i;//5.1.4 如果沒有就緒的描述符,就繼續poll監測,否則繼續向下看if(--ret <= 0)continue;}//5.2繼續響應就緒的描述符for(i=1; i<=maxi; i++){if(client[i].fd < 0)continue;if(client[i].revents & (POLLIN | POLLERR)){int len = 0;char buf[128] = "";//5.2.1接受用戶端資料if((len = recv(client[i].fd, buf, sizeof(buf), 0)) < 0){if(errno == ECONNRESET)//tcp連線逾時、RST{close(client[i].fd);client[i].fd = -1;}elseperror("read error:");}else if(len == 0)//用戶端關閉串連{close(client[i].fd);client[i].fd = -1;}else//正常接收到伺服器的資料send(client[i].fd, buf, len, 0);//5.2.2所有的就緒描述符處理完了,就退出當前的for迴圈,繼續poll監測if(--ret <= 0)break;}}}return 0;}
運行結果:
源碼下載:
Linux網路編程——tcp並發伺服器(poll實現)