#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数:
- fds:监听的文件描述符【数组】
struct pllfd {int fd; 待监听的文件描述符short events; 待监听的文件描述符对应的监听事件short revents; 传入时,给0; 如果满足对应事件的话,返回非0
}
- nfds:监听数组的,实际有效监听个数
- 超时时长。单位:毫秒
//server.c
#include <unistd.h>#define SERV_PROT 8000
#define MAXLINE 80
#define OPEN_MAX 1024int main(int argc, char *argv[])
{int i, J, maxi, listenfd, connfd, sockfd;int nread;ssize_t n;char buf[MAXLINE], str[INET_ADDRSTRLEN]; //INE_ADDRSTRLEN 16socklen_t clilen;struct pollfd client[OPEN_MAX];struct sockaddr_in cliaddr, seraddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&serv_addr, sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);serv_addr.sin_port = htons(SERV_PROT);Bind(listen, (struct sockaddr*)&serv_addr, sizeof(serv_addr));Listen(listenfd, 128);client[0].fd = listenfd; //要监听的第一个文件描述符存入client[0]client[0].events = POLLIN; //listen监听普通读事件for (i = 1; i < OPEN_NAX; ++i)client[i].fd = -1; //用-1初始化client[]里剩下, 0也是文件描述符,不能用mxi = 0; //client[]数组有效元素中最大元素的下标for ( ; ; ){nread = poll(client, maxi + 1, -1); //阻塞监听是否有客户端连接请求if (client[0].revents & POLLIN) //listen有读事件就绪{clilen = sizeof(cliaddr);connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); //接受客户端请求Accept不会阻塞printf("receive from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));for (i = 1; i < OPEN_MAX; i++)if (client[i].fd < 0){client[i].fd = connfd; //找到client[]中空闲的位置,存放accept返回的connfdbreak;}if (i == OPEN_MAX) //达到最大客户端perr_exit("too many client");client[i].events = POLLIN; //设置刚返回的connfd监控读事件if (i > maxi)maxi = i; //更新client[]中最大元素下标if (--nread <= 0)continue; //没有更多就绪事件时, 继续回到poll阻塞}for (i = 1; i < maxi; i++){if ((sockfd = client[i].fd) < 0)continue;if (client[i].revents & POLLIN){if (n = Read(sockfd, buf, MAXLINE)) < 0){if (errno == ECONNRESET) //收到RST标志{printf("client[%d] aborted connection\n", i);Close(sockfd);client[i].fd = -1; //poll中不监控该文件描述符,直接置为-1即可,不用像select中那样移除}elseperr_exit("read error");}else if (n == 0) //说明客户端先关闭链接{printf("client[%d] closed connection\n", i);Close(sockfd);clent[i].fd = -1;}else{for (j = 0; j < n; ++j)buf[j] = toupper(buf[j]);Write(sockfd, buf, n);if (--nread <= 0)break;}}}}return 0;
}