linux poll函数的使用

在网络编程中,Linuxpoll函数跟select一样,可以处理多路复用。可以通过设置关注的描述符事件,灵活等待事件的到来。

 

#include <poll.h>

 

       int poll(struct pollfd *fds, nfds_t nfds, int timeout);

 

      

(1)参数fdspollfd结构体指针,可以指向一个结构体数组

 

 struct pollfd {

       int   fd;  /* file descriptor */

       short events;  /* requested events */

       short revents;  /* returned events */

   };

 

pollfd结构体成员的fd设置为需要关注的描述符,当fd被赋值为-1(负数)时,表示忽略 eventsrevents事件也将被设置成0

 

pollselect不同(select函数在调用之后,会清空检测描述符的数组),每当调用这个函数之后,系统不会清空这个数组,而是将有状态变化的描述符结构的revents变量状态变化,操作起来比较方便

 

 events是需要设置进去对fd的关注事件(关注可读、可写、异常),属于掩码(可以或),比如设置成POLLIN | POLLOUT,关注可读可写。

 

revents是由内核通知的,函数返回的时候,会设置对应的fd实际发生的事件,比如fd有可读的事件,设置POLLIN

 

常量

说明

是否可以作为输入

是否可以作为输出

POLLIN

普通或优先级带数据可读

POLLRDNORM

普通数据可读(等价POLLIN,与linux版本有关)

POLLRDBAND

优先级带数据可读(linux中一般不用)

POLLPRI

高优先级数据可读

POLLOUT

普通数据可写

POLLWRNORM

普通数据可写(等价POLLOUT,与linux版本有关)

POLLWRBAND

优先级数据可写

POLLRDHUP

Linux2.6.17以上才支持,需要声明_GNU_SOURCEtcp被被对方关闭连接,对方关闭了写操作

POLLERR

发生错误

POLLHUP

挂起

POLLNVAL

描述字不是一个打开的文件

 

表格中的最后三个是不能作为events事件注册进去的,只能放到revents结果中。

(2)nfds_t nfds,  nfds是描述符个数,结构体pollfd数组元素的个数

(3)timeout(单位毫秒)参数设置为-1时,表示永远阻塞等待。0表示立即返回,不阻塞。大于0时,表示等待指定数目的毫秒数

 

(4) poll返回值

大于0:表示结构体数组fds中有fd描述符的状态发生变化,或可以读取、或可以写入、或出错。并且返回的值表示这些状态有变化的socket描述符的总数量;此时可以对fds数组进行遍历,以寻找那些revents不空的描述符,然后判断这个里面有哪些事件以读取数据。

等于0:表示没有描述符有状态变化,并且调用超时。

小于0:此时表示有错误发生,此时全局变量errno保存错误码。

 

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>		  /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>  
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <poll.h>

extern int errno;

#define  MaxConnectNum (5)

int main()
{
	int domain = AF_INET;
	int type = SOCK_STREAM;
	int protocol = 0;
	int ret  = -1;
	int nListenFd = -1;
	int nNewClientFd = -1;
	short int  port = 2000; 
	struct sockaddr_in addr_in;
	int backlog = 128; // 默认是128
	int len = 0;
	char chBuffer[1024] = {0};
	int flags = 0;
	int nMaxFd = -1;
	int i = 0;
	static int s_nCountClient = 0;
	struct pollfd  stuPollFd[MaxConnectNum+1];
	
	nListenFd = socket( domain,  type,  protocol);
	if(nListenFd < 0)
	{
		printf("\n socket failed ! errno[%d]  err[%s]\n", errno, strerror(errno));
		return -1;
	}

	memset(&addr_in, 0, sizeof(struct sockaddr_in));
	addr_in.sin_family = AF_INET;
	addr_in.sin_port = htons(port);//htons的返回值是16位的网络字节序整型数   htons尾的字母s代表short
	addr_in.sin_addr.s_addr = htonl(INADDR_ANY);

	ret = bind(nListenFd, ( struct sockaddr * )(&addr_in), sizeof(struct sockaddr_in));
    if(ret < 0)
    {
    	printf("\n bind failed ! errno[%d]  err[%s]\n", errno, strerror(errno));
    	close(nListenFd); //避免资源泄漏
		return -1;
	}

    ret = listen(nListenFd, backlog);
    if(ret < 0)
    {
		printf("\n listen failed ! errno[%d]	err[%s]\n", errno, strerror(errno));
		close(nListenFd); //避免资源泄漏
		return -1;
	}

	nMaxFd = 1;
	memset(stuPollFd, 0, sizeof(stuPollFd));

	stuPollFd[0].fd = nListenFd;
	stuPollFd[0].events |= POLLIN;

	for(i = 1; i <= MaxConnectNum; i++)
	{
		stuPollFd[i].fd = -1;
	}
	
	while(1)
	{
		int time_out_ms = 3000;
		int num = 0;

	    num = poll(stuPollFd, nMaxFd , time_out_ms);
		if(num > 0)
		{
			printf("\n  num =%d\n",num);
			for(i = 1; i <= MaxConnectNum; i++)
			{
				if((stuPollFd[i].fd != -1) && (POLLIN & stuPollFd[i].revents))
				{
					len = recv(stuPollFd[i].fd, chBuffer, sizeof(chBuffer) , flags);//flags为0,阻塞模式
					if(len <= 0)
					{
						printf("\n recv failed ! errno[%d]	err[%s] len[%d]\n", errno, strerror(errno),len);
					//	close(nListenFd); //避免资源泄漏
						close(stuPollFd[i].fd);
					    stuPollFd[i].events = 0;
						s_nCountClient--;
						stuPollFd[i].fd = -1;
						
						//return -1;
						continue;
					}

					printf("\n i[%d] fd[%d] chBuffer[%s] \n", i, stuPollFd[i].fd , chBuffer);
				}
			}

			if(POLLIN & stuPollFd[0].revents)
			{
				nNewClientFd = accept(nListenFd, ( struct sockaddr *)NULL, NULL); //阻塞模式
				if(nNewClientFd < 0)
				{
					printf("\n accept failed ! errno[%d]	err[%s]\n", errno, strerror(errno));
					//close(nListenFd); //避免资源泄漏
					break;
				}

				if(s_nCountClient >= MaxConnectNum)
				{
					close(nNewClientFd);

					printf("\n s_nCountClient >= MaxConnectNum \n");
					continue;
				}

				printf("\n new   client  nNewClientFd[%d]\n",nNewClientFd);
				s_nCountClient++;
				
				for(i = 1; i <= MaxConnectNum; i++)
				{
					if(stuPollFd[i].fd == -1)
					{
						stuPollFd[i].fd = nNewClientFd;
						stuPollFd[i].events = 0;
						stuPollFd[i].events |= POLLIN;

						if(i >= nMaxFd )
						{
							nMaxFd = i+1;
						}
						break;
					}
				}
			
			}
		}
		else if(num == 0)
		{
			printf("\n time out \n");
			//return 0;
		}
		else
		{
			printf("\n error  \n");
			break;
		}

	}

	for(i = 1; i <= MaxConnectNum; i++)
	{
		if(stuPollFd[i].fd != -1)
		{
			close(stuPollFd[i].fd);
		}
	}
	close(stuPollFd[0].fd);

	return 0;
}



客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>		  /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>  
#include <errno.h>
#include <unistd.h>

extern int errno;

int main()
{
	int domain = AF_INET;//AF_INET
	int type = SOCK_STREAM;
	int protocol = 0;
	int ret  = -1;
	int nClientFd = -1;
	short int  port = 2000; 
	struct sockaddr_in addr_in;
	int len = 0;
	char chBuffer[1024] = {0};
	int flags = 0;
	char * pchServerIP = "192.168.1.211";
	
	nClientFd = socket( domain,  type,  protocol);
	if(nClientFd < 0)
	{
		printf("\n socket failed ! errno[%d]  err[%s]\n", errno, strerror(errno));
		return -1;
	}

    memset(&addr_in, 0, sizeof(struct sockaddr_in));
	addr_in.sin_family = AF_INET;
	addr_in.sin_port = htons(port);//htons的返回值是16位的网络字节序整型数   htons尾的字母s代表short
	//addr_in.sin_addr.s_addr = htonl(inet_addr(pchServerIP)); //错误的做法
	addr_in.sin_addr.s_addr = inet_addr(pchServerIP); 
	ret = connect(nClientFd, ( struct sockaddr * )(&addr_in), sizeof(struct sockaddr_in));
    if(ret < 0)
    {
    	printf("\n connect failed ! errno[%d]  err[%s]\n", errno, strerror(errno));
    	close(nClientFd); //避免资源泄漏
		return -1;
	}

	printf("\n  connect success ! \n");
	for(;;)
	{
		len = send(nClientFd, "2", sizeof("2"), flags); 
		sleep(2);
	}
	
	close(nClientFd);

	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值