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;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux IO复用是指在处理多个I/O事件时,通过一种机制使得一个进程可以同时监听多个I/O操作,从而提高程序的效率和性能。 在Linux系统中,常用的IO复用机制有三种:select、poll和epoll。 1. select:select函数是最早引入的IO复用机制之一,它通过传入一组文件描述符集合,来监听这些文件描述符上是否有事件发生。当其中任意一个文件描述符上有事件发生时,select函数就会返回,然后程序可以通过遍历文件描述符集合来判断哪些文件描述符上有事件发生。 2. pollpoll函数是对select的改进,其使用方式和select类似。不同的是,poll函数使用一个pollfd结构数组来存储待监听的文件描述符及其对应的感兴趣事件,通过调用poll函数时传入这个数组来实现IO复用。相对于select,poll没有最大文件描述符数量的限制,并且效率更高。 3. epoll:epollLinux下最新的IO复用机制,它提供了更加高效的IO事件通知机制。epoll使用一个文件描述符来管理被监听的其他文件描述符,通过调用epoll_ctl函数向这个文件描述符中注册或者删除需要监听的文件描述符。当某个文件描述符上有事件发生时,epoll_wait函数会返回该文件描述符的相关信息给程序处理。相对于select和poll,epoll在处理大量连接时具有更好的性能。 总结来说,Linux IO复用机制可以让一个进程同时监听多个I/O事件,避免了使用阻塞IO时的等待时间,提高了程序的效率和性能。而select、poll和epoll是常用的IO复用机制。其中,epoll是效率最高的一种机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值