一:poll系统调用
同select相似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪者。
二:poll函数
1.函数原型:
#include<poll.h>
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
2.函数参数:
先来了解一下struct pollfd这个结构体
struct pollfd
{
int fd; //文件描述符
short events; //注册的事件
short revents; //实际发生的事件,由内核填充。
}
/*其中fd成员指定文件描述符;events成员告诉poll监听fa上的那些事件,它是一系列事件的按位或;
revents则有内核修改,以通知应用程序fd上实际发生了那些事件。*/
①fds: | pollfd结构类型的数组,指定我们所有感兴趣的文件描述符上发生的可读,可写,异常等事件。 |
②ndfs: | 指定被监听事件集合fds的大小。(其类型位:typedef unsigned long int nfds_t;) |
③timeout: | 设置超时时间,单位毫秒。 -1:poll将永远阻塞 0:poll调用将立即返回。 |
三:逻辑思想
四:测试代码
服务器端:
//poll.c
#define _GNU_SOURCE
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<poll.h>
#define SIZE 100
void Delete_fd(struct pollfd *fds , int fd)
{
int i=0;
for(;i<SIZE;++i)
{
if(fds[i].fd == fd)
{
fds[i].fd = -1;
fds[i].events = 0;
// fds[i].revents = 0;
}
}
}
void Init_fd(struct pollfd *fds)
{
int i = 0;
for(;i<SIZE;++i)
{
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
}
}
void Insert_fd(struct pollfd *fds,int fd,short event)
{
int i= 0 ;
for(;i<SIZE;++i)
{
if(fds[i].fd == -1)
{
fds[i].fd = fd;
fds[i].events = event;
break;
}
}
}
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -1);
struct sockaddr_in ser,cli;
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(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res != -1);
listen(sockfd,5);
struct pollfd fds[SIZE];
Init_fd(fds);
Insert_fd(fds,sockfd,POLLIN);
while(1)
{
int n = poll(fds,SIZE,-1);
if(n<=0)
{
printf("poll fail!!!\n");
continue;
}
int i = 0;
for(;i<SIZE;++i)
{
if(fds[i].fd != -1)
{
int fd = fds[i].fd;
if(fds[i].revents & POLLRDHUP)//这个应该放到前面
{
close(fd);
Delete_fd(fds,fd);
printf("%d: will close\n",fd);
}
else if(fds[i].revents & POLLIN)
{
if(fd == sockfd)
{
int len = sizeof(cli);
int c = accept(sockfd,(struct sockaddr*)&cli,&len);
if(c<=0)
{
printf("accept is fail\n");
continue;
}
Insert_fd(fds,c,POLLIN|POLLRDHUP);
}
else
{
char buff[128]={0};
int n =recv(fds[i].fd,buff,127,0);
if(n<=0)
{
close(fds[i].fd);
Delete_fd(fds,fds[i].fd);
printf("%d: is close\n",fd);
}
else
{
printf("%d: %s\n",fd,buff);
send(fd,"OK",2,0);
}
}
}
}
}
}
close(sockfd);
}
客户端:
#include"../../apue.h"
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
assert(sockfd != -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 = connect(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res != -1);
while(1)
{
printf("please input:\n");
fflush(stdout);
char buf[128]={0};
fgets(buf,127,stdin);
buf[strlen(buf)-1] = 0;
if(strcmp(buf,"end") == 0)
{
break;
}
send(sockfd,buf,strlen(buf),0);
printf("send is OK\n");
// char recvbuff[128] = {0};
// recv(sockfd,recvbuff,127,0);
// printf("%s:\n",recvbuff);
}
close(sockfd);
}