poll函数

poll函数原型

image
image
三个分别是:待监听的文件描述符、待监听的文件描述符对应的监听事件、传入时给0,如果满足对应事件的话返回非0,
nfds:监听数组的实际有效的监听个数
超时时长:单位毫秒

代码

/*************************************************************************
	> File Name: server.c
	> Author: shaozheming
	> Mail: 957510530@qq.com
	> Created Time: 2022年03月05日 星期六 10时48分07秒
 ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <errno.h>

#include "wrap.h"

#define SERV_PORT 6666
#define MAXLINE 80
#define OPEN_MAX 1024
#define INET_ADDRSTRLEN 16

int main(int argc, char* argv[])
{
	int i, j, nready;
	int maxi;
	ssize_t n;

	int listenfd, connfd, sockfd;

	char buf[BUFSIZ], str[INET_ADDRSTRLEN];   //数据缓冲区

	struct sockaddr_in clie_addr, serv_addr;  //服务端和客户端socket
	socklen_t clie_addr_len;
	struct pollfd client[OPEN_MAX]; //poll结构体数组

	listenfd = Socket(AF_INET, SOCK_STREAM, 0); //设置tcp

	int opt = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); //设置端口复用

	bzero(&serv_addr, sizeof(serv_addr)); //清0
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(SERV_PORT);

	Bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); //bind绑定

	Listen(listenfd, 128); //设置监听数量
	
	client[0].fd = listenfd;
	client[0].events = POLLIN;  //第一个文件描述符。监听读事件

	for(i = 1; i < OPEN_MAX; ++i)
		client[i].fd = -1;

	maxi = 0; //client数组中最大元素下标

	while(1) {
		nready = poll(client, maxi+1, -1); //阻塞监听
	
		if(client[0].revents & POLLIN) {
			/* listenfd有读事件 */	
			connfd = Accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len); //connfd通信

			printf("received from %s at PORT %d \n", 
					inet_ntop(AF_INET, &clie_addr.sin_addr, str, sizeof(str)), 
					ntohs(clie_addr.sin_port));
			
			for( i = 1; i < OPEN_MAX; ++i) {
				if(client[i].fd < 0) {
					client[i].fd = connfd; //连接
					break;
				}
			}

			/* 达到了最大监听数 */
			if( i == OPEN_MAX) perr_exit("too many clients!\r\n");

			client[i].events = POLLIN; //设置刚刚返回的连接读事件
			if(i > maxi) maxi = i;
			if(--nready <= 0) continue;
		}

		for(i = 1; i <= maxi; ++i) {
		/* 检测connfd */
			if((sockfd = client[i].fd) < 0) 
				continue;

			if(client[i].revents & POLLIN) {
				
				if((n = Read(sockfd, buf, MAXLINE)) < 0) {
					if(errno == ECONNRESET) {
					/* 收到复位标志 */
						printf("client[%i] aborted connection\r\n", i);
						Close(sockfd);
						client[i].fd = -1;
					} else {
						perr_exit("read error\r\n");
					}
				} else if(n == 0) {	
					printf("client[%i] closed connection\r\n", i);
					Close(sockfd);
					client[i].fd = -1;
				} else {
					for( j = 0; j < n; j++){
						buf[j] = toupper(buf[j]);
					}
					Writen(sockfd, buf, n);
				}
				if(--nready <= 0)
					break;
			} 
		}
	}
    return 0;
}

poll的优点和缺点

优点:
自带数组结构,可以将监听事件集合和返回事件集合分离
可以拓展监听上限
缺点:
不能跨平台,只有linux
无法直接定位满足监听事件的文件描述符

突破1024文件描述符限制

查看文件描述符上限(当前计算机所能打开的,受硬件影响):
cat /proc/sys/fs/file-max
也可以使用ulimit -a,当前默认能打开的
修改:
sudo vi /etc/security/limits.conf
文件尾部加入(软限制和硬限制)

  • soft nofile 65536
  • hard nofile 100000
    软限制不能超过硬限制
    修改ulimit中的, ulimit -n (修改值),改完之后要注销用户使其生效
posted @   蘑菇王国大聪明  阅读(91)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示