Linux C编程 poll IO复用
poll 简介
select前情回顾
select 优点:
目前几乎在所有平台上支持,良好的跨平台性是它的一个优点。
select 缺点:
1.每次调用select(),都需要把fd的集合从用户态拷贝到内核态,及每次轮询完,都需要重新初始化fds集合。
这个开销在fd很多时会很大,同时每次select都需要在内核遍历传递进来的所有fd,这个开销在fd很多的时候很大。
2.单个进程能够监视的文件描述符存在最大的限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式
提升这一个限制,但是这样也会造成效率的降低。
poll函数简介
select() 和 poll() 系统调用的本质一样,poll()的机制与select()类似,与select()在本质上没有多大差别,管理多个
描述符也是进行轮询的机制,根据描述符的状态进行处理,但是poll()没有最大文件描述符数量的限制(但是数量过大后
性能 也是会下降)poll() 和 select() 同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核
的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
poll编程
poll函数简介
1.poll 函数
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//功能:监视并等待文件描述符的返回
- 参数:
参数 | 名称 | 说明 |
---|---|---|
fds | 文件描述符结构体 | 传入为 struct pollfd的数组 |
nfds | 用来指定第一个参数数组元素个数 | 即fds数组的大小 |
timeout | 超过规定时间后唤醒 | 超过规定时间后唤醒 |
- 返回值
成功时,poll() 返回结构体中 revents 域不为 0 的文件描述符个数;
如果在超时前没有任何事件发生,poll()返回 0;
失败时,poll() 返回 -1,并设置 errno 为下列值之一: - 结构体
poll函数中的 struct pollfd结构体
struct pollfd{
int fd; //文件描述符
short events; //指定监测fd的事件(输入、输出、错误),每一个事件有多个取值,
short revents; //events 域是文件描述符的操作结果事件,内核在调用返回时设置这个域。
//events 域中请求的任何事件都可能在 revents 域中返回.
};
参数:
poll 编程示例:
//tcp_poll_cilent.c
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <poll.h>
#define MAXBUFF 1024
static void usaAge(char * proc)
{
printf("Please enter: %s [send_ip] [send_port\n",proc);
}
int main(int argc,char *argv[])
{
int socked,new_fd;
socklen_t sender_len;
int sendBuf_len=0;
int recvBUf_len=0;
struct sockaddr_in sender;
struct pollfd fds[2];
int retval=0;
char sendBuf[MAXBUFF+1];
sender_len=sizeof(sender);
if(argc==1)
{
usaAge(argv[0]);
}
bzero(&sender,sizeof(sender));
sender.sin_family=AF_INET;
if(argv[1])
{
sender.sin_addr.s_addr=inet_addr(argv[1]);
}
else
{
sender.sin_addr.s_addr=htonl(INADDR_ANY);
}
if(argv[2])
{
sender.sin_port=htons(atoi(argv[2]));
}
else
{
sender.sin_port=htons(8888);
}
socked=socket(AF_INET,SOCK_STREAM, 0);
if(socked<0)
{
perror("socket failed");
}
if (connect(socked, (struct sockaddr *) &sender, sizeof(sender)) != 0)
{
perror("Connect ");
exit(EXIT_FAILURE);
}
else
{
printf("Get connect,ip is :%s port is %d\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port));
}
printf("\nget ready pls chat\n");
fds[0].fd=0;
fds[1].fd=socked;
fds[0].events=POLLIN;
fds[1].events=POLLIN;
while(1)
{
retval=poll(fds,2,1000);
if(retval==-1)
{
perror("select failed");
exit(EXIT_FAILURE);
}
else if(retval==0)
{
printf("Timeout\n");
}
else
{
if(( fds[0].revents & POLLIN ) == POLLIN )
{
printf("You can sendMessage\n");
memset(sendBuf,0,MAXBUFF+1);
fgets(sendBuf,MAXBUFF,stdin);
if(!strncasecmp(sendBuf,"quit",4))
{
printf("I will quit\n");
break;
}
sendBuf_len=send(socked,sendBuf,strlen(sendBuf)-1,0);
if (sendBuf_len > 0)
printf ("send successful,%d byte send!\n",sendBuf_len);
else
{
printf("send failure!");
break;
}
}
if(( fds[1].revents & POLLIN ) == POLLIN)
{
printf("Receive Message\n");
bzero(sendBuf, MAXBUFF + 1);
recvBUf_len=recv(socked,sendBuf,MAXBUFF,0);
if (recvBUf_len > 0)
printf ("recv success :'%s',%dbyte recv\n", sendBuf, recvBUf_len);
else
{
printf("receive failure!");
break;
}
}
}
}
close(socked);
return 0;
}
//tcp_poll_server.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <poll.h>
#define MAXBUFF 1024
static void usaAge(char * proc)
{
printf("Please enter: %s [local_ip] [local_port] [listnum]\n",proc);
}
int main(int argc,char *argv[])
{
int socked,new_fd;
int listnum;
socklen_t sender_len;
int sendBuf_len=0;
int recvBUf_len=0;
struct sockaddr_in myaddr,sender;
struct pollfd fds[2];
int retval=0;
char sendBuf[MAXBUFF+1];
sender_len=sizeof(sender);
if(argc==1)
{
usaAge(argv[0]);
}
bzero(&myaddr,sizeof(myaddr));
myaddr.sin_family=AF_INET;
if(argv[1])
{
myaddr.sin_addr.s_addr=inet_addr(argv[1]);
}
else
{
myaddr.sin_addr.s_addr=htonl(INADDR_ANY);
}
if(argv[2])
{
myaddr.sin_port=htons(atoi(argv[2]));
}
else
{
myaddr.sin_port=htons(8888);
}
if(argv[3])
{
listnum=atoi(argv[3]);
}
else
{
listnum=5;
}
socked=socket(AF_INET,SOCK_STREAM,0);
if(socked==-1)
{
perror("socket failed");
}
if(bind(socked,(struct sockaddr*)&myaddr,sizeof(myaddr))<0)
{
perror("bind error");
}
if (listen(socked, listnum) == -1)
{
perror("listen error");
}
else
{
printf("listen ok\n");
}
while(1)
{
new_fd=accept(socked,(struct sockaddr*)&sender,&sender_len);
if(new_fd<0)
{
perror("accept error");
}
else
{
printf("Get connectls,ip is :%s port is %d\n",inet_ntoa(sender.sin_addr),ntohs(sender.sin_port));
}
fds[0].fd=0;
fds[1].fd=new_fd;
fds[0].events=POLLIN;
fds[1].events=POLLIN;
while(1)
{
retval=poll(fds,2,1000);
if(retval==-1)
{
perror("select failed");
exit(EXIT_FAILURE);
}
else if(retval==0)
{
printf("Timeout\n");
}
else
{
if((fds[0].revents & POLLIN ) == POLLIN )
{
printf("You can sendMessage\n");
memset(sendBuf,0,MAXBUFF+1);
fgets(sendBuf,MAXBUFF,stdin);
if(!strncasecmp(sendBuf,"quit",4))
{
printf("I will quit\n");
break;
}
sendBuf_len=send(new_fd,sendBuf,strlen(sendBuf)-1,0);
if (sendBuf_len > 0)
printf ("send successful,%d byte send!\n",sendBuf_len);
else {
printf("send failure!");
break;
}
}
if(( fds[1].revents & POLLIN ) == POLLIN)
{
printf("Receive Message\n");
bzero(sendBuf, MAXBUFF + 1);
recvBUf_len=recv(new_fd,sendBuf,MAXBUFF,0);
if (recvBUf_len > 0)
printf ("recv success :'%s',%dbyte recv\n", sendBuf, recvBUf_len);
else
{
printf("receive failure!");
break;
}
}
}
}
close(new_fd);
printf("need other connect\n");
fflush(stdout);
bzero(sendBuf,MAXBUFF+1);
fgets(sendBuf, MAXBUFF, stdin);
if (!strncasecmp(sendBuf, "no", 2))
{
printf("quit!\n");
break;
}
}
close(socked);
return 0;
}