目录
poll API
poll系统调用 和 select类似,也是在指定时间内轮询一定数量的文件描述符,以测试其中是否有就绪事件。
poll的原型如下:
头文件:#include <poll.h>
int poll (struct pollfd * fds ,nfds_t nfds ,int timeout)
fds参数:pollfd结构类型的数组,它指定所有我们感兴趣的文件描述上发生的可读、可写和异常等事件。
pollfd结构体的定义如下:
struct pollfd
{
int fd; //文件描述符
short events; //注册的事件
short revents; //实际发生的事件,由内核填充
};
- 成员fd:指定文件描述符;
- 成员events:告诉poll监听fd上的那些事件,它是一系列事件的按位或;
- 成员revents:由内核修改,通知应用程序fd上实际发生了那些事件;
poll支持的事件如下表所示:
事件 | 描述 | 是否可作为输入 | 是否可作为输出 |
---|---|---|---|
POLLWRNORM | 普通数据可写 | 是 | 是 |
POLLWRBAND | 优先数据可写 | 是 | 是 |
POLLRDHUP | tcp连接被对方关闭,或者对方关闭了写操作,它由GNU引入 | 是 | 是 |
POLLERR | 错误 | 否 | 是 |
POLLHUP | 挂起。比如管道的写端被关闭后,读端描述符上将收到POLLHUP事件 | 否 | 是 |
POLLNVAL | 文件描述符没有打开 | 否 | 是 |
POLLIN | 数据(包括普通数据和优先数据)可读 | 是 | 是 |
POLLRDNORM | 普通数据可读 | 是 | 是 |
POLLRDBAND | 优先级带数据可读(Linux不支持) | 是 | 是 |
POLPRI | 高级优先数据可读,比如tcp带外数据 | 是 | 是 |
POLLOUT | 数据(包括普通数据和优先数据)可写 | 是 | 是 |
参数nfds:指定被监听事件集合fds的大小,其类型nfds_t的定义如下:
typedef unsigned long int nfds_t;
参数timeout:指定poll的超时值,单位是毫秒。当timeout为-1时,poll调用将阻塞,直到某个事件发生;当timeout为0时,poll调用将立即返回;
poll 编程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/time.h>
#define FD_MAX 10
int socket_init();
void fds_init(struct pollfd fds[])
{
for( int i = 0; i < FD_MAX; i++ )
{
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
}
}
void fds_add( struct pollfd fds[], int fd)
{
for( int i = 0; i < FD_MAX; i++ )
{
if ( fds[i].fd == -1 )
{
fds[i].fd = fd;
fds[i].events = POLLIN;//注册读事件
fds[i].revents = 0;
break;
}
}
}
void fds_del( struct pollfd fds[], int fd)
{
for( int i = 0; i < FD_MAX; i++ )
{
if ( fds[i].fd == fd )
{
fds[i].fd = -1;
fds[i].events = 0;
fds[i].revents = 0;
break;
}
}
}
int main()
{
int sockfd = socket_init();
if( sockfd == -1 )
{
printf("socket init failed\n");
exit(1);
}
struct pollfd fds[FD_MAX];
fds_init(fds);
fds_add(fds,sockfd);
while( 1 )
{
int n = poll(fds,FD_MAX,5000);
if ( n < 0 )
{
printf("poll err\n");
}
else if ( n == 0 )
{
printf("time out\n");
}
else
{
for( int i = 0; i < FD_MAX; i++ )
{
if ( fds[i].fd == -1 )
{
continue;
}
if ( fds[i].revents & POLLIN )
{
if ( fds[i].fd == sockfd )
{
struct sockaddr_in caddr;
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
if ( c < 0 )
{
continue;
}
printf("accept c=%d\n",c);
fds_add(fds,c);//新的连接套接字添加到fds,-》poll
}
else
{
char buff[128] = {0};
int num = recv(fds[i].fd,buff,127,0);
if ( num <= 0 )
{
close(fds[i].fd);
fds_del(fds,fds[i].fd);
printf("client close\n");
}
else
{
printf("recv(%d):%s\n",fds[i].fd,buff);
send(fds[i].fd,"ok",2,0);
}
}
}
}
}
}
}
int socket_init()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if( sockfd == -1 )
{
return -1;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if ( res == -1 )
{
return -1;
}
res = listen(sockfd,5);
if ( res == -1 )
{
return -1;
}
return sockfd;
}