poll函数
poll函数与select函数的功能基本一样,其定义如下:
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
struct pollfd{
int fd; //文件描述符
short events; //请求的事件
short revents; //返回的事件
};
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于 socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select() 函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因 此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
poll() 函数不会受到socket描述符上的O_NDELAY标记和O_NONBLOCK标记的影响和制约,也就是说,不管socket是阻塞的还是非阻塞 的,poll()函数都不会收到影响;而select()函数则不同,select()函数会受到O_NDELAY标记和O_NONBLOCK标记的影 响,如果socket是阻塞的socket,则调用select()跟不调用select()时的效果是一样的,socket仍然是阻塞式TCP通讯,相 反,如果socket是非阻塞的socket,那么调用select()时就可以实现非阻塞式TCP通讯;
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/un.h>
#include<sys/wait.h> //*进程用的头文件*/
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<poll.h> //包含poll的头文件 #define MAXLINE 1024 //通信内容的最大长度 #ifndef FD_SETSIZE
#define FD_SETSIZE 25 //select最多能处理的文件描述符
#endif ssize_t readn(int fd, void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nread;
char *charbuf=(char*) buf; while(nleft>)
{
nread=read(fd,charbuf,nleft);
if(nread<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nread==)
return count-nleft; charbuf +=nread;
nleft=count-nread;
}
return count;
} ssize_t writen(int fd, const void *buf, size_t count)
{
ssize_t nleft=count;
ssize_t nwrite;
char *charbuf=(char*) buf; while(nleft>)
{
nwrite=write(fd,charbuf,nleft);
if(nwrite<)
{
if(errno==EINTR)
continue;
return -;
}
else if(nwrite==)
return count-nleft;
charbuf +=nwrite;
nleft=count-nwrite; }
return count;
} ssize_t recv_peek(int sockfd, void *buf, size_t len)
{
int ret;
while()
{
ret=recv(sockfd,buf,len,MSG_PEEK);
if(ret==-&& errno==EINTR)
continue;
return ret;
}
} ssize_t readline(int sockfd, void *buf, size_t len)
{
ssize_t nleft=len,nread;
int ret;
char* bufchar=buf;
while()
{
ret=recv_peek(sockfd,bufchar,len);
if(ret<||ret==)
return ret;
nread=ret;
int i;
for(i=;i<nread;i++)
{
if(bufchar[i]=='\n')
{
ret=readn(sockfd,bufchar,i+);
if(ret!=i+)
exit(EXIT_FAILURE);
return ret;
}
}
if(nread>nleft)
exit(EXIT_FAILURE);
nleft-=nread;
ret=readn(sockfd,bufchar,nread);
if(ret!=nread)
exit(EXIT_FAILURE);
bufchar+=nread; }
return -; } int main()
{
int sock_fd,new_fd,fd;//sock_fd用于监听,new_fd用于连接
int maxi;
struct pollfd client[FD_SETSIZE];//用于存放客户端描述符
int nready;//检测到的事件数
struct sockaddr_in srv_addr;//服务器的地址信息
struct sockaddr_in client_addr;//客户机的地址信息
int i,size; //地址结构数据的长度
fd_set rset,allset;
char sendbuf[],recvbuf[];
memset(sendbuf,,sizeof(sendbuf));
memset(recvbuf,,sizeof(recvbuf)); /*创建套接字*/
sock_fd=socket(AF_INET,SOCK_STREAM,);//采用IPv4协议
if(sock_fd==-)
{
perror("creat socket failed");
exit();
} /*服务器地址参数*/
srv_addr.sin_family=AF_INET;
srv_addr.sin_port=htons();
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
bzero(&srv_addr.sin_zero,sizeof(struct sockaddr_in));//bzero位清零函数,将sin_zero清零,sin_zero为填充字段,必须全部为零 int on=; //表示开启reuseaddr
if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))<) //打开地址、端口重用
perror("setsockopt"); /*绑定地址和端口*/
if(bind(sock_fd,(struct sockaddr*)&srv_addr,sizeof(struct sockaddr))==-)
{
perror("bind failed");
exit();
} /*设置监听模式,等待客户机的监听*/
if((listen(sock_fd,))==-)
{
perror("listen failed");
exit();
} int maxi=;
client[].fd=sock_fd; //将监听套接字放在数组中
client[].events=POOLIN; //感兴趣的事件为数据可读
for(i=;i<FD_SETSIZE;i++)
client[i].fd=-; //描述符为-1表示空闲 //使用poll实现并发服务器
while()
{
nready=poll(client,maxi+,-); //超时时间为-1,表示阻塞直到检测到事件
if(nready==-)
{
if(errno==EINTR) //因为信号中断退出
continue;
perror("select\n");
}
else if(nready==) //超时
{
continue;
} if(client[].revents & POLLIN) //监听套接口产生可读
{
size=sizeof(struct sockaddr_in);
new_fd=accept(sock_fd,(struct sockaddr*)&client_addr,&size); /*接受连接,采用非阻塞是的模式调用accep*/
if(new_fd==-)
{
perror("accept failed");
//continue;//restart accept when EINTR
} printf("server:got connection from IP= %s prot= %d \n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));//连接成功,打印客户机IP地址和端口号
/*char *inet_nota(struct sockaddr_in in);
头文件:
arpa/inet.h
Winsock2.h
参数:
一个网络上的IP地址
返回值:
如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。
uint31_t ntohs(uint32_t net32bitvalue);
头文件:
#include<netinet/in.h>
把net32bitvalue有网络字节序转换为主机字节序。
*/
if(send(new_fd,"Hello client,I am 192.168.229.125!\n",,)==-) //192.168.229.125为子进程IP,可更改
perror("send failed");
for(i=;i<FD_SETSIZE;i++) //检测已连接套接字中是否有套接字产生 {
if(client[i].fd<)
{
client[i].fd=new_fd; //将描述符保存在某一个空闲的位置
break;
}
if(i==FD_SETSIZE) //没有找到空闲的位置,即描述符个数达到上限
perror("too many client");
if(i>maxi)
maxi=i;
client[i].events=POLLIN;
if(--nready<=) //若检测到的套接口已经处理完,则继续用poll监听
continue;
} for(i=;i<=maxi;i++)
{
if((fd=client[i].fd)<)
continue;
if(client[i].revents & POLLIN) //连接套接口产生事件
{
memset(recvbuf,,sizeof(recvbuf));
if((n=readline(fd,recvbuf,MAXLINE))==)
{
printf("client closed\n");
close(fd);
client[i].fd=-;
}
else if(n==-)
perror("readline\n");
else
{
writen(fd,recvbuf,n);
fputs(recvbuf,stdout);
} if(--nready<=)
break;
}
} }
}
poll函数的更多相关文章
- linux poll函数
poll函数与select函数差不多 函数原型: #include <poll.h> int poll(struct pollfd fd[], nfds_t nfds, int timeo ...
- poll()函数的使用
分类: LINUX poll函数用于监测多个等待事件,若事件未发生,进程睡眠,放弃CPU控制权,若监测的任何一个事件发生,poll将唤醒睡眠的进程,并判断是什么等待事件发生,执行相应的操作.poll函 ...
- select与poll函数介绍
select与poll函数介绍 在所有依从POSIX的平台上,select函数使我们可以执行I/O多路转接.传向select的参数告诉内核: 1)我们所关心的描述符 2)对于每个描述符我们所关心的状态 ...
- I/O多路复用——select函数与poll函数
1 区别 同:(1)机制类似,本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理.(2)包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就 ...
- poll函数和串口设置
2015.1.24 今天星期六,多云,早晨8:17起床的,今天是来南京起床最迟的一天,因为昨晚睡得有点迟,今天又不用上课,整个人有点放松.收拾好来到教室,教室门没有开,胡明也到了,其他人还在宿舍睡觉, ...
- [转载] poll()函数
原地址:http://baike.baidu.com/view/2997591.htm poll()函数:这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函 ...
- I/O多路转接之poll 函数
poll 一.poll()函数: 这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,自认为poll和select大同小异,下面是这个函数的声明: #include < ...
- UNIX网络编程——select函数的并发限制和 poll 函数应用举例
一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置, ...
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...
随机推荐
- [Unity3D][转] 关于Assets资源目录结构管理
分享个我们项目常用的目录结构,微调过很多次,最终到了这个版本.个人认为这种管理资源方式是不错的.欢迎探讨各个细节~ 更新于2013.5.30 Asserts --Editor 自写的灵活方便插 ...
- struts2进阶篇(2)
一.Action与MVCstruts2是一个基于MVC的web应用框架,它将应用程序分为三个组件:模型,视图,控制器.模型:包含了应用程序的业务逻辑和业务数据,由封装数据和处理业务的javaBean组 ...
- Orchard源码分析(4.2):Orchard.Logging.LoggingModule类
与CollectionOrderModule一样,LoggingModule也是一个Autofac模块.它以属性注入的方式给需要日志服务的对象设置Logger. 如果一个类有Orchard.Lo ...
- C++ compile issue
You can do so via right-click -> Properties on a file or a selection of files in Solution Explore ...
- iOS9 适配
iOS适配的相关内容的整理 之前iOS开发者一直很庆幸自己不用像安卓开发者那样适配各种不同类型的机型,但如今随着iPhone各种机型的改变,适配也成了我们开发中必须会的内容了.首先我们来了解一下对于不 ...
- php怎么获取mac地址?
如何用php获取mac地址呢?大家知道mac地址是电脑在全球范围的唯一标识,所以这个就非常实用,比如说要做一个投票功能,那mac地址是必不可少 的,如果单纯的靠ip地址来判断这个肯定是不准确的,水分太 ...
- oracle 中的round()函数、null值,rownum
round()函数:四舍五入函数 传回一个数值,该数值按照指定精度进行四舍五入运算的结果. 语法:round(number[,decimals]) Number:待处理的函数 Decimals:精度, ...
- vue-cli + webpack 多页面实例应用
关于vue.js vue.js是一套构建用户界面的 轻型的渐进式前端框架.它的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件.使用vue可以给你的开发带来极致的编程体验. 关于vu ...
- Oracle的分区操作和修改分区主键
1.增加一个分区ALTER TABLE sales ADD PARTITION jan96 VALUES LESS THAN ( '01-FEB-1999' ) TABLESPACE tsx;增加一个 ...
- poj.1988.Cube Stacking(并查集)
Cube Stacking Time Limit:2000MS Memory Limit:30000KB 64bit IO Format:%I64d & %I64u Submi ...