____________________________________________
poll提供的功能与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,但poll比select的优点是,不限制所能监视的描述符的数目,但随着所监视描述符的数目的增加,性能也会下降
函数原型:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
返回值:成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,返回0;失败返回-1
参数:
fds:结构体指针,该结构体结构如下:
struct pollfd{
int fd; //所感兴趣的文件描述符
short events; //用于指定等待的事件
short revents; //用于指定poll返回时,在该文件描述符上实际发生了的事件
};
每一个pollfd结构体制定了一个被监视文件描述符,可传递多个该结构体,指示poll监视多个文件描述符
nfds:要监视的描述符的个数
timeout:单位(微秒),timeout指定等待的毫秒数,无论I/O是否准备好,poll都会返回,指定为负数值表示无限超时,使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件,立即返回
events域中请求的任何事件都可能在revents域中返回。合法的事件如下:
POLLIN 有数据可读
POLLPRI 有紧迫数据可读
POLLOUT 写数据不会导致阻塞
POLLRDNORM 有普通数据可读。
POLLRDBAND 有优先数据可读。
POLLWRNORM 写普通数据不会导致阻塞。
POLLWRBAND 写优先数据不会导致阻塞。
POLLMSGSIGPOLL 消息可用。
此外,revents域中还可能返回下列事件:
POLLER 指定的文件描述符发生错误。
POLLHUP 指定的文件描述符挂起事件。
POLLNVAL 指定的文件描述符非法。
这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。
POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events为POLLIN |POLLOUT。在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果POLLIN事件被设置,则文件描述符可以被读取而不阻塞。如果POLLOUT被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读取和写入操作都会正常返回而不阻塞。
示例代码如下:
编写一个echo server程序,功能是客户端向服务器发送信息,服务器接收输出并原样发送回给客户端,客户端接收到输出到终端
server_poll.c
void usage(char *_proc)
{
printf("%s [ip] [port]\n",_proc);
}
int create(char *_ip,int _port)
{
int listen_fd=socket(AF_INET,SOCK_STREAM,0);
if(listen_fd<0){
perror("socket");
exit(1);
}
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
struct linger lig;
int iLen;
lig.l_onoff=1;
lig.l_linger=0;
iLen=sizeof(struct linger);
setsockopt(listen_fd,SOL_SOCKET,SO_LINGER,(char *)&lig,iLen);
if(bind(listen_fd,(struct sockaddr*)&local,sizeof(local))<0){
perror("bind");
exit(2);
}
if(listen(listen_fd,_BLOCKLOG_)<0){
perror("listen");
exit(3);
}
return listen_fd;
}
int main(int args,char *argv[])
{
if(args!=3){
usage(argv[0]);
return 1;
}
char *ip=argv[1];
int port=atoi(argv[2]);
//创建监听描述符并绑定
int listen_fd=create(ip,port);
nfds_t nfds=64;
struct pollfd fds[nfds];
//初始化描述符
int i=