一、使用
int poll(struct pollfd *fds,int nfds,int timeout);
(1) struct pollfd
{
int fd; //关注的文件描述符
short events; // 关注的是文件描述符上的哪种事件
short revents; // 由内核修改的,返回此文件描述符上发生的事件类型(必须是events指定的关注的事件)
(2)nfds:数组的长度
(3)timeout: 超时时间 -1 代表阻塞,直到有事件发生
二、代码
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <poll.h>
#define FDMAXNUM 100
void InitFds(struct pollfd *fds)
{
int i = 0;
for(; i < FDMAXNUM; ++i)
{
fds[i].fd = -1;
}
}
void DeleteFd(int fd, struct pollfd *fds)
{
int i = 0;
for(; i < FDMAXNUM; ++i)
{
if(fds[i].fd == fd)
{
fds[i].fd = -1;
break;
}
}
}
void AddFd(int fd, struct pollfd *fds)
{
int i = 0;
for(; i < FDMAXNUM; ++i)
{
if(fds[i].fd == -1)
{
fds[i].fd = fd;
fds[i].events = POLLIN | POLLRDHUP;
break;
}
}
}
void GetClientLink(int fd, struct pollfd *fds)
{
struct sockaddr_in cli;
int len = sizeof(cli);
int c = accept(fd, (struct sockaddr*)&cli, &len);
if(c == -1)
{
return;
}
AddFd(c, fds);
}
void DealClientData(int fd, struct pollfd *fds, int rdhup)
{
if(rdhup) //断开链接
{
close(fd);
DeleteFd(fd, fds);
return;
}
char buff[128] = {0};
int n = recv(fd, buff, 127, 0);
if(n <= 0)
{
DeleteFd(fd, fds);
return;
}
printf("%s\n", buff);
send(fd, "OK", 2, 0);
}
int main()
{
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd != -1);
struct sockaddr_in ser;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(6000);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(listenfd, (struct sockaddr*)&ser, sizeof(ser));
assert(res != -1);
listen(listenfd, 5);
struct pollfd fds[FDMAXNUM];
InitFds(fds);
fds[0].fd = listenfd;
fds[0].events = POLLIN;
while(1)
{
int n = poll(fds, FDMAXNUM, -1);
if(n <= 0)
{
exit(0);
}
int i = 0;
for(; i < FDMAXNUM; ++i)
{
if(fds[i].fd == -1)
{
continue;
}
if(fds[i].fd == listenfd && fds[i].revents & POLLIN)
{
GetClientLink(fds[i].fd, fds);
}
else if(fds[i].revents & POLLIN)
{
if(fds[i].revents & POLLRDHUP)
DealClientData(fds[i].fd, fds, 1);
else
DealClientData(fds[i].fd, fds, 0);
}
}
}
}
三、优点
1、将用户关注的事件与内核修改的就绪事件分割开,每次调用poll不需要重新设置
2、poll通过int类型记录文件描述符,文件描述符的取值范围扩大到系统最大限制 65535
3、用户关注的所有文件描述符通过fds指向的用户数组来记录,则可以关注的文件描述符由用户自己指定,能扩大到系统最大限制
四、缺点
1、返回值返回就绪的文件描述符个数, poll也仅仅是在fds指向的数组元素中标记出哪个文件描述符就绪
用户探测就绪文件描述符的时间复杂度依旧是O(n)
2、内核依旧采用轮询方式处理