poll开发服务器

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

函数说明:与select类似,委托内核监控可读,可写,异常事件。

函数说明:

fds:一个struct pollfd结构体数组的首地址

struct pollfd {
               int   fd;         要监控的文件描述符
               short events;     输入参数,告诉内核要监控的可读,可写,异常事件
               short revents;    输出参数,内核告诉应用程序改变的文件描述符
           };

events/revents:
 POLLIN :可读事件

 POLLOUT:可写事件

 POLLERR:异常事件

nfds:要监控的文件描述符的数量,最大数组下标+1

timeout:

=0:不阻塞,立刻返回

-1:表示一直阻塞,直到事件发生

>0:表示阻塞时长,在时长范围内若有事件发生就会立刻返回

时间到也会返回。 

 开发流程:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include <sys/types.h> 
#include <netinet/in.h>
#include<ctype.h>
#include <poll.h>
#include <signal.h>
#include<errno.h>

int main()
{
	//int socket(int domain, int type, int protocol);
	int lfd=socket(AF_INET,SOCK_STREAM ,0);
	if(lfd<0)
	{
		perror("socket error");
		return -1;
	}
	// int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
	int opt=1;
	setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
	//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
	struct sockaddr_in sev;
	sev. sin_family=AF_INET;
	sev. sin_port=htons(8888);
	inet_pton(AF_INET,"192.168.230.130",&sev.sin_addr.s_addr);
	int ret=bind(lfd,(struct sockaddr*)&sev,sizeof(sev));
	if(ret<0)
	{
		perror("bind error");
		return -1;
	}
	ret=listen(lfd,128);
	if(ret<0)
	{
		perror("listen error");
		return -1;
	}
	struct pollfd fds[1024];//定义数组
	int i;
	int cfd;
	int nready;
	int maxi = 0;一开始的最大下标
	int x;
	int j;
	int sockfd;
	char buf[64];
	int n;
	for(i=0;i<1024;i++)
	{
		fds[i].fd=-1;//把数组的fd全部初始化为-1,表示该位置空闲
	}

	fds[0].fd=lfd;//在位置零处存放lfd监听文件描述符,让内核监控lfd
	fds[0].events=POLLIN;//监听可读事件
	struct sockaddr_in client;//客户端地址
	socklen_t len;
	len=sizeof(client);
	char sIP[16];
	while(1)
	{
		nready=poll(fds,maxi+1,-1); //maxi表示监控文件描述符的数量
		if(nready < 0)
		{
			if(errno==EINTR)//被信号打断
			{
				continue;
			}
			break;
		}

		if(fds[0].revents==POLLIN)//lfd发生变化,有客户端请求连接
		{
			cfd=accept(lfd,(struct sockaddr*)&client,&len);
			for(i=1;i<1024;i++)//遍历数组元素
			{
				if(fds[i].fd==-1)//值为-1说明位置空闲
				{
					memset(sIP,0x00,sizeof(sIP));
					printf("client:ip==[%s],port==[%d] is connect\n",inet_ntop(AF_INET,&client.sin_addr.s_addr,sIP,sizeof(sIP)),ntohs(client.sin_port));
					fds[i].fd=cfd;//加入数组,让内核监控此cfd
					fds[i].events=POLLIN;//监控可读事件
					break;//退出for循环
				}
			}
			if(i==1024)
			{
				printf("there is no space\n");
				close(cfd);
				continue;
			}
			if(maxi < i)
			{
				maxi = i;//更新最大数组下标
			}
           if(--nready==0)
           {
                continue;//可读事件为0,继续while循环,不用进行下面的操作
           }
		}

		for(x=1;x<=maxi;x++)//从数组开始循环
		{
			sockfd=fds[x].fd;
			if(sockfd==-1)
			{
				continue;//无效,继续循环
			}

			if(fds[x].revents==POLLIN)
			{
				memset(buf,0x00,sizeof(buf));
				n=read(sockfd,buf,sizeof(buf));
				if(n<=0)
				{
					printf("read error or client close, n==[%d]\n",n);
					close(sockfd);//关闭文件描述符
					fds[x].fd=-1;//移除,让内核不监控此文件描述符
				}
				else //n>0的情况
				{
					printf("[%d]n==[%d],buf==[%s]\n",x,n,buf);
					for(j=0;j<n;j++)
					{
						buf[j]=toupper(buf[j]);
					}
					write(sockfd,buf,n);
				}
				if(--nready==0)
				{
					break;
				}
			}
		}
	}

	close(lfd);
	return 0;
}

结果:

 

由结果可见 删除1位置时,重新连接的客户端是从位置1连接的,说明数组位置充分使用 

注意:

1 当poll函数返回时,结构体当中的fd和events没有发生变化,究竟有没有事件发生由revents来判断,所以poll是请求和返回分离。

2 struct pollfd结构体中fd成员赋值为-1,则内核不会对这个文件描述符进行监控

相关推荐

  1. 1. 使用poll或epoll创建echo服务器

    2024-03-10 00:30:01       53 阅读
  2. 高并发服务器 poll模型 非阻塞 讲解

    2024-03-10 00:30:01       51 阅读
  3. 多路IO复用服务器——select模型和poll模型

    2024-03-10 00:30:01       52 阅读
  4. Linux下网络编程-简易poll服务器和客户端

    2024-03-10 00:30:01       26 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-10 00:30:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-10 00:30:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-10 00:30:01       82 阅读
  4. Python语言-面向对象

    2024-03-10 00:30:01       91 阅读

热门阅读

  1. 【数论】欧拉筛

    2024-03-10 00:30:01       39 阅读
  2. 贪心算法介绍

    2024-03-10 00:30:01       42 阅读
  3. EDA 许可证调度

    2024-03-10 00:30:01       41 阅读
  4. ArrayList和linkedList的区别精简概述

    2024-03-10 00:30:01       53 阅读
  5. 安全防范之警惕钓鱼邮件

    2024-03-10 00:30:01       48 阅读
  6. 2024年,程序员如何破局?

    2024-03-10 00:30:01       46 阅读
  7. SQL基础知识复习及示例语句

    2024-03-10 00:30:01       42 阅读
  8. vue3+vite

    2024-03-10 00:30:01       34 阅读
  9. python深拷贝和浅拷贝

    2024-03-10 00:30:01       39 阅读
  10. 如何快速的搭建一个小程序

    2024-03-10 00:30:01       55 阅读
  11. unity中摄像机跟随

    2024-03-10 00:30:01       44 阅读
  12. Error running ‘Attach debug to process‘

    2024-03-10 00:30:01       42 阅读
  13. BDD测试框架Cucumber学习

    2024-03-10 00:30:01       38 阅读
  14. C# 的一些好用的语法糖介绍

    2024-03-10 00:30:01       41 阅读