poll函数
poll函数原型
三个分别是:待监听的文件描述符、待监听的文件描述符对应的监听事件、传入时给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 (修改值),改完之后要注销用户使其生效
主要是给自己看的,所以肯定会出现很多错误哈哈哈哈哈
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律