LINUX下poll函数用法
文章目录
一、函数介绍
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
第一个参数为一个结构体数组,它存储需要监听的文件描述符和需要监听的事件。
结构体定义如下
struct pollfd {
int fd; /* 待监听的文件描述符*/
short events; /* 待见听的事件*/
short revents; /* 返回事件的结果*/
};
events取值POLLIN、POLLOUT、POLLERR分别代表传入传出和错误。
revents可在定义时传入0,满足事件后,回返回POLLIN、POLLOUT、POLLERR。
第二个参数nfds:监听数组的实际有效个数。
第三个参数timeout:超时时长,
传入-1则阻塞等待。
传入0则立即返回,不阻塞进程。
传入>0则等待指定时间,单位为毫秒。
返回值:返回满足对应监听时间的总个数。
二、使用
1.
我写了一个简单的例子,在这个例子中我只监听了套接字的read请求,并将收到的数据进行回显。
文中大写字母开头的函数为我自己重新封装的函数,用法与原来相同并自动检查返回值。我将它放到另一个文件中。
#include "ddd.h"
#include <poll.h>
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <signal.h>
int main()
{
struct pollfd fdds[1024]; //定义待监听的文件描述符集合
char buf[100]; //定义缓冲区
socklen_t ss_len;
struct sockaddr_in addr,ss;
int socket_fd,r_fd;
socket_fd=Socket(AF_INET,SOCK_STREAM,0);
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(4500);
int e;
int opt=1;
setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//设置套接字为复用
Bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr));
//绑定套接字
if ((e=listen(socket_fd,128))==-1)
{
my_error("socket_fd",__LINE__);
}
int maxfd=0;//最大可用套接字的下标
int selet_ret;
maxfd=0;
fdds[0].fd=socket_fd;//先将监听用的套接字传入集合中
fdds[0].events=POLLIN;
int j=0;
for (j=1;j<1024;j++)
{
fdds[j].fd=-1; //初始化套接字集合为空
}
int i;
while(1)
{
selet_ret=poll(fdds,maxfd+1,-1); //使用poll监测多个等待事件
if(selet_ret<0)
{
my_error("select",__LINE__);
exit(1);
}
if (fdds[0].revents&POLLIN) //监听是否有connect请求
{
ss_len=sizeof(ss);
r_fd=accept(socket_fd,(struct sockaddr *)&ss,&ss_len);
printf("ip:%s port: %u\n",inet_ntoa(ss.sin_addr),ntohs(ss.sin_port));
for (i=1;i<1024;i++) //找到最小的未使用的文件描述符并break;
{
if (fdds[i].fd<0)
{
fdds[i].fd=r_fd;
fdds[i].events=POLLIN;
break;
}
}
if (r_fd>maxfd)
{
maxfd=r_fd;
}
if (--selet_ret<0) //若事件只有connect则回到poll处等待其他事件
{
continue;
}
}
for(i=1;i<=maxfd;i++) //逐个查看哪个套接字有请求并处理
{
if (fdds[i].fd==-1)
{
continue;
}
if (fdds[i].revents&POLLIN)
{
int ret;
ret=read(fdds[i].fd,buf,sizeof(buf));
if (ret==0)
{
close(i);
fdds[i].fd=-1;
}
else if (ret<0)
{
my_error("read",__LINE__);
}
write(fdds[i].fd,buf,ret);
write(STDOUT_FILENO,buf,ret);
}
if (--selet_ret<=0)
{
break;
}
}
}
close(socket_fd);
return 0;
}
#ifndef _DDD_H_
#define _DDD_H_
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include<errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/time.h>
void my_error(const char *error_string, int line); //错误处理函数
int Socket(int domain, int type, int protocol);
int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
#endif
#include "ddd.h"
void my_error(const char *error_string, int line) //错误处理函数
{
fprintf(stderr, "line:%d",line);
perror(error_string);
exit(1);
}
int Socket(int domain, int type, int protocol)
{
int ret;
ret = socket(domain, type, protocol);
if (ret < 0)
{
my_error("socket",__LINE__);
exit(1);
}
else return ret;
}
int Connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
{
int ret =connect(sockfd,addr,addrlen);
if (ret<0)
{
my_error("connect",__LINE__);
exit(1);
}
else return 0;
}
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
{
int ret=bind(sockfd,my_addr,addrlen);
if (ret < 0)
{
my_error("bind",__LINE__);
exit(1);
}
}
int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int ret=accept(s,addr,addrlen);
if (ret < 0)
{
my_error("accpet",__LINE__);
exit(1);
}
else return ret;
}