#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 1024
int 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 16
socklen_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返回的connfd
break;
}
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中那样移除
}
else
perr_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;
}