【Linux】select、poll、epoll代码

    

  将fd设置成非阻塞

void setNonBlock(int fd)
{int res = fcntl(fd, F_GETFL);if (res < 0){std::cerr << "错误" << strerror(errno) << std::endl;return;}fcntl(fd, F_SETFL, res | O_NONBLOCK);
}

select

1.select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;

2.程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变; 

select函数原型 

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

参数解释 

参数nfds是需要监视的最大的文件描述符值+1;

rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合、可写文件描述符的集合及异常文件描述符的集合;

参数timeout为结构timeval,用来设置select()的等待时间

参数timeout取值: 

NULL:则表示select()没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件;

0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。

特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。

关于fd_set结构 

其实fd_set这个结构就是一个整数数组, 更严格的说, 是一个 "位图". 使用位图中对应的位来表示要监视的文件描述符.提供了一组操作fd_set的接口, 来比较方便的操作位图

void FD_CLR(int fd, fd_set *set);      // 用来清除描述词组set中相关fd 的位  
int  FD_ISSET(int fd, fd_set *set);    // 用来测试描述词组set中相关fd 的位是否为真  
void FD_SET(int fd, fd_set *set);      // 用来设置描述词组set中相关fd的位   
void FD_ZERO(fd_set *set);             // 用来清除描述词组set的全部位

 理解select执行过程

(1) 执行fd_set set; FD_ZERO(&set);则set用位表示是0000,0000。

(2) 若fd=5,执行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)

(3) 若再加入fd=2,fd=1,则set变为0001,0011

(4) 执行select(6,&set,0,0,0)阻塞等待

(5) 若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。

注意:没有事件发生的fd=5被清空。

select缺点 

1.每次调用select, 都需要手动设置fd集合, 从接口使用角度来说也非常不便.

2.每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

3.同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

4.select支持的文件描述符数量太小.

 selectServer代码

#pragma once#include "sock.hpp"
#include <algorithm>
#include <functional>
int max(int a, int b)
{return a > b ? a : b;
}
namespace select_cbr
{static const int default_port = 8080;static const int fd_num = sizeof(fd_set) * 8;static const int defaultfd = -1;using func = std::function<std::string(const std::string &)>;class SelectServer{public:SelectServer(func funct, int port = default_port) : _func(funct), _port(port), _listensock(-1), _fdarray(nullptr){}void initServer(){_listensock = Sock::Socket();Sock::Bind(_listensock, _port);Sock::Listen(_listensock);_fdarray = new int[fd_num];for (int i = 0; i < fd_num; i++)_fdarray[i] = defaultfd;_fdarray[0] = _listensock;}void Print(){std::cout << "fd list: ";logMessage(DEBUG, "fd[0]==%d", _fdarray[0]);for (int i = 0; i < fd_num; i++){if (_fdarray[i] != defaultfd)std::cout << _fdarray[i] << " ";}std::cout << std::endl;}void Accepter(int listensock){std::string clientIp;uint16_t clientPort;int sock = Sock::Accept(listensock, &clientIp, &clientPort);if (sock < 0)return;logMessage(NORMAL, "accept success [%s:%d]", clientIp.c_str(), clientPort);int i = 0;for (; i < fd_num; i++){if (_fdarray[i] == defaultfd)break;}if (i == fd_num){logMessage(WARNING, "server if full, please wait");close(sock);}else{_fdarray[i] = sock;}Print();}void Recver(int sock, int pos){logMessage(DEBUG, "in recver");char buffer[1024];ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);logMessage(DEBUG, "s===%d", s);if (s > 0){buffer[s] = 0;logMessage(NORMAL, "client# %s", buffer);}else if (s == 0){close(sock);_fdarray[pos] = defaultfd;logMessage(NORMAL, "client quit");return;}else{close(sock);_fdarray[pos] = defaultfd;logMessage(ERROR, "client quit: %s", strerror(errno));return;}std::string response = _func(buffer);write(sock, response.c_str(), response.size());logMessage(DEBUG, "out recver");}void HanderEvent(fd_set &rfds){for (int i = 0; i < fd_num; i++){if (_fdarray[i] == defaultfd)continue;if (FD_ISSET(_fdarray[i], &rfds) && _fdarray[i] == _listensock){logMessage(DEBUG, "1111");Accepter(_listensock);}else if (FD_ISSET(_fdarray[i], &rfds)){logMessage(DEBUG, "2222");Recver(_fdarray[i], i);}}}void start(){int cnt = 1;while (1){fd_set rfds;FD_ZERO(&rfds);int maxfd = 0;for (int i = 0; i < fd_num; i++){if (_fdarray[i] == defaultfd)continue;FD_SET(_fdarray[i], &rfds);maxfd = max(maxfd, _fdarray[i]);}logMessage(DEBUG, "maxfd===%d", maxfd);// struct timeval timeout = {0, 0};int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);logMessage(DEBUG, "cnt==%d", cnt);cnt++;if (n == -1){logMessage(WARNING, "select error,code:%d,err string:%s", errno, strerror(errno));}else if (n == 0){logMessage(NORMAL, "timeout...");}else{logMessage(NORMAL, "get a new link....");HanderEvent(rfds);}sleep(1);}}~SelectServer(){if (_listensock < 0)close(_listensock);if (_fdarray)delete[] _fdarray;}private:int _port;int _listensock;int *_fdarray;func _func;};
}

poll

poll函数接口

 #include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

 pollfd结构

struct pollfd {  int    fd;         /* file descriptor */ short  events;     /* requested events */   short  revents;    /* returned events */
};

参数说明 

fds是一个poll函数监听的结构列表. 每一个元素中, 包含了三部分内容: 文件描述符, 监听的事件集合, 返回的事件集合.

nfds表示fds数组的长度.

timeout表示poll函数的超时时间, 单位是毫秒(ms).

pollServer代码 

#pragma once#include "sock.hpp"
#include <algorithm>
#include <functional>
#include <poll.h>
int max(int a, int b)
{return a > b ? a : b;
}
namespace poll_cbr
{static const int default_port = 8080;static const int defaultfd = -1;static const int fd_num = 2048;using func = std::function<std::string(const std::string &)>;class PollServer{public:PollServer(func funct, int port = default_port) : _func(funct), _port(port), _listensock(-1), _rfds(nullptr){}void ResetItem(int pos){_rfds[pos].fd = defaultfd;_rfds[pos].events = 0;_rfds[pos].revents = 0;}void initServer(){_listensock = Sock::Socket();Sock::Bind(_listensock, _port);Sock::Listen(_listensock);_rfds = new struct pollfd[fd_num];for (int i = 0; i < fd_num; i++){ResetItem(i);}_rfds[0].fd = _listensock;_rfds[0].events = POLLIN;}void Print(){std::cout << "fd list: ";logMessage(DEBUG, "fd[0]==%d", _rfds[0].fd);for (int i = 0; i < fd_num; i++){if (_rfds[i].fd != defaultfd)std::cout << _rfds[i].fd << " ";}std::cout << std::endl;}void Accepter(){std::string clientIp;uint16_t clientPort;int sock = Sock::Accept(_listensock, &clientIp, &clientPort);if (sock < 0)return;logMessage(NORMAL, "accept success [%s:%d]", clientIp.c_str(), clientPort);int i = 0;for (; i < fd_num; i++){if (_rfds[i].fd == defaultfd)break;}if (i == fd_num){logMessage(WARNING, "server if full, please wait");close(sock);}else{_rfds[i].fd = sock;_rfds[i].events = POLLIN;_rfds[i].revents = 0;}Print();}void Recver(int pos){logMessage(DEBUG, "in recver");char buffer[1024];ssize_t s = recv(_rfds[pos].fd, buffer, sizeof(buffer) - 1, 0);logMessage(DEBUG, "s===%d", s);if (s > 0){buffer[s] = 0;logMessage(NORMAL, "client# %s", buffer);}else if (s == 0){close(_rfds[pos].fd);ResetItem(pos);logMessage(NORMAL, "client quit");return;}else{close(_rfds[pos].fd);ResetItem(pos);logMessage(ERROR, "client quit: %s", strerror(errno));return;}std::string response = _func(buffer);write(_rfds[pos].fd, response.c_str(), response.size());logMessage(DEBUG, "out recver");}void HanderEvent(){for (int i = 0; i < fd_num; i++){if (_rfds[i].fd == defaultfd)continue;if (!(_rfds[i].events & POLLIN))continue;if (_rfds[i].fd == _listensock && (_rfds[i].revents & POLLIN))Accepter();else if (_rfds[i].revents & POLLIN)Recver(i);}}void start(){int timeout = -1;while (1){int n = poll(_rfds, fd_num, timeout);if (n == -1){logMessage(WARNING, "poll error,code:%d,err string:%s", errno, strerror(errno));}else if (n == 0){logMessage(NORMAL, "timeout...");}else{logMessage(NORMAL, "get a new link....");HanderEvent();}sleep(1);}}~PollServer(){if (_listensock < 0)close(_listensock);if (_rfds)delete[] _rfds;}private:int _port;int _listensock;struct pollfd *_rfds;func _func;};
}

epoll

epoll的相关系统调用        

int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

epollServer

#pragma once#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <sys/epoll.h>
#include "err.hpp"
#include "log.hpp"
#include "sock.hpp"namespace epoll_cbr
{static const int defaultport = 8888;static const int size = 128;static const int defaultvalue = -1;static const int defalultnum = 64;using func_t = std::function<std::string(const std::string &)>;class EpollServer{public:EpollServer(func_t f, uint16_t port = defaultport, int num = defalultnum): func_(f), _num(num), _revs(nullptr), _port(port), _listensock(defaultvalue), _epfd(defaultvalue){}void initServer(){// 1. 创建socket_listensock = Sock::Socket();Sock::Bind(_listensock, _port);Sock::Listen(_listensock);// 2. 创建epoll模型_epfd = epoll_create(size);if (_epfd < 0){logMessage(FATAL, "epoll create error: %s", strerror(errno));exit(EPOLL_CREATE_ERR);}// 3. 添加listensock到epoll中struct epoll_event ev;ev.events = EPOLLIN | EPOLLET;ev.data.fd = _listensock;epoll_ctl(_epfd, EPOLL_CTL_ADD, _listensock, &ev);// 4. 申请就绪事件的空间_revs = new struct epoll_event[_num];logMessage(NORMAL, "init server success");}void HandlerEvent(int readyNum){logMessage(DEBUG, "HandlerEvent in");for (int i = 0; i < readyNum; i++){uint32_t events = _revs[i].events;int sock = _revs[i].data.fd;if (sock == _listensock && (events & EPOLLIN)){//_listensock读事件就绪, 获取新连接std::string clientip;uint16_t clientport;int fd = Sock::Accept(sock, &clientip, &clientport);if (fd < 0){logMessage(WARNING, "accept error");continue;}// 获取fd成功,放入epollstruct epoll_event ev;ev.events = EPOLLIN;ev.data.fd = fd;epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);}else if (events & EPOLLIN){// 普通的读事件就绪char buffer[1024];int n = recv(sock, buffer, sizeof(buffer), 0);logMessage(DEBUG, "n==%d", n);if (n > 0){buffer[n] = 0;logMessage(DEBUG, "client# %s", buffer);std::string response = func_(buffer);send(sock, response.c_str(), response.size(), 0);}else if (n == 0){// 先从epoll移除,再close fdepoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);close(sock);logMessage(NORMAL, "client quit");}else{// 先从epoll移除,再close fdepoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);close(sock);logMessage(ERROR, "recv error, code: %d, errstring: %s", errno, strerror(errno));}}else{}}logMessage(DEBUG, "HandlerEvent out");}void start(){int timeout = -1;while (1){int n = epoll_wait(_epfd, _revs, _num, timeout);switch (n){case 0:logMessage(NORMAL, "timeout ...");break;case -1:logMessage(WARNING, "epoll_wait failed, code: %d, errstring: %s", errno, strerror(errno));break;default:logMessage(NORMAL, "have event ready");HandlerEvent(n);break;}}}~EpollServer(){if (_listensock != defaultvalue)close(_listensock);if (_epfd != defaultvalue)close(_epfd);if (_revs)delete[] _revs;}private:uint16_t _port;int _listensock;int _epfd;struct epoll_event *_revs;int _num;func_t func_;};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670445.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ESP32+Python】WIFI连接包括固定账号密码+选择WIFI在输入密码

import network import time# 创建WLAN对象 wlan network.WLAN(network.STA_IF)def scan_and_display_wifi_networks():# 激活接口wlan.active(True)# 扫描附近的WiFi网络networks wlan.scan()print("可用的WiFi网络&#xff1a;")for i, net in enumerate(network…

leetcode 744.寻找比目标字母大的最小字母

本题是二分查找板块中的一个简单题目&#xff0c;不过二分查找比较注重于细节。所以我会着重点出来。 思考&#xff1a;从查找字母这一个要求来说&#xff0c;我们要么选择遍历&#xff0c;要么选择二分查找&#xff0c;因为这里是非递减的&#xff0c;那么我们自然的就会想到…

Flink 动态表 (Dynamic Table) 解读

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

鸿蒙 WiFi 扫描流程(2)

接着上篇没有记录完的&#xff0c;我们继续梳理&#xff0c;需要上一篇做基础的请看&#xff1a;鸿蒙 WiFi 扫描流程&#xff08;1&#xff09; 上一篇我们讲到 scan_service.cpp 里面的 SingleScan 方法&#xff0c;继续这个方法往下看&#xff1a; // foundation/communicat…

Python基础知识:Python函数的定义、创建与调用

Python本质上是一种编程语言&#xff0c;通过编写运行代码的方式实现工作目标。读者可以想象&#xff0c;如果针对机器学习或数据统计分析的每种方法或统计量计算都要用户自行编写代码&#xff0c;那么显然在很多情况下是无法满足用户便捷开展分析的要求的&#xff0c;用户体验…

docer compose部署simple-docker

简介 一个看似简陋但是功能足够用的docker管理工具 安装 创建目录 mkdir -p /opt/simple-docker cd /opt/simple-docker 创建并启动容器 编写docker-compose.yml文件,内容如下 version: 3 services: redis: image: redis:latest restart: always web: image: registry.cn-…

HR看了都想点开的简历:吸睛模板+撰写技巧

工作致富的第一步&#xff1a;写一份好的简历。一个独特、简单、清晰的个人简历模板可以更好地吸引雇主的注意和兴趣&#xff0c;并帮助你在许多求职者中脱颖而出。如何制作一份令人印象深刻的简历&#xff1f;巧妙地使用个人简历模板是一个不错的选择。在本文中&#xff0c;我…

线性代数:矩阵的初等变换

目录 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理 一、初等行变换 行阶梯 / 行最简 性质 二、矩阵的标准型 三、矩阵的等价 四、初等矩阵 五、重要性质与定理

Java快速输入输出的实现

在Java编程中&#xff0c;我们经常需要从标准输入读取数据&#xff0c;或者将结果输出到标准输出。为了提高输入输出的效率&#xff0c;我们可以使用快速输入输出的方法。下面是一个示例类Read&#xff0c;它提供了一系列方法来实现快速的输入输出操作。 import java.io.*;cla…

Git - 每次 git pull/push 时需要账号和密码解决方案

问题描述 在提交项目代码或者拉取代码的时候&#xff0c;每次 git 都要输入用户名密码&#xff0c;很烦~ 解决方案 让服务器记下来用户名和密码&#xff0c;此时输入一次&#xff0c;以后再 git push /pull 的时候就不用再输账号和密码了 # 配置 git 记录用户名和密码 git c…

租游戏服务器多少钱1个月?一年价格多少?

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

SpringBoot注解--04--01--注解@Mapper在IDEA中自动注入警告的解决方案

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 问题原因 解决方案方法1&#xff1a;为 Autowired 注解设置required false方法2&#xff1a;用 Resource 替换 Autowired方法3&#xff1a;在Mapper接口上加上Repo…

跟着pink老师前端入门教程-day19

一、移动WEB开发之流式布局 1、 移动端基础 1.1 浏览器现状 PC端常见浏览器&#xff1a;360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 移动端常见浏览器&#xff1a;UC浏览器&#xff0c;QQ浏览器&#xff0c;欧朋浏览器&#xff0…

论文阅读-Transformer-based language models for software vulnerability detection

「分享了一批文献给你&#xff0c;请您通过浏览器打开 https://www.ivysci.com/web/share/biblios/D2xqz52xQJ4RKceFXAFaDU/ 您还可以一键导入到 ivySCI 文献管理软件阅读&#xff0c;并在论文中引用 」 本文主旨&#xff1a;本文提出了一个系统的框架来利用基于Transformer的语…

Kubernetes实战(二十五)-快速下载k8s.gcr.io,gcr.io,quay.io镜像

1 背景 在云计算和云原生的环境下&#xff0c;不可避免的会使用很多镜像创建容器&#xff0c;其中有些镜像只有谷歌镜像仓库才有&#xff0c;但是国内不可以直接下载谷歌仓库的镜像&#xff0c;下面推荐几种方法&#xff0c; k8s.gcr.io/gcr.io 是谷歌的镜像仓库&#xff0c;…

LaTeX基本公式语法

Markdown支持通过LaTeX插入复杂的数学公式。 行内公式与块级公式 行内公式&#xff1a;使用一对美元符号$...$标记&#xff1a; 欧拉公式可以表示为 e i π 1 0 e^{i\pi} 1 0 eiπ10&#xff0c;这是一个著名的等式。 块级公式&#xff1a;使用一对双美元符号$$...$$标记…

宠物空气净化器适合养猫家庭吗?除猫毛好的猫用空气净化器推荐

宠物掉毛是一个普遍存在的问题&#xff0c;尤其在脱毛季节&#xff0c;毛发似乎无处不在。这给家中的小孩和老人带来了很多麻烦&#xff0c;他们容易流鼻涕、过敏等不适。此外&#xff0c;宠物有时还会不规矩地拉扯和撒尿&#xff0c;这股气味实在是难以忍受。家人们对宠物的存…

Java——Arrays常用方法

Arrays常用方法 Java 中的 Arrays 类提供了一系列静态方法&#xff0c;可以用来操作数组。 1. sort() 方法——默认升序排序 Arrays.sort() 方法用于对数组进行排序。该方法有多个重载版本&#xff0c;可以对不同类型的数组进行排序。 public static void sort(int[] arr) …

算法学习——LeetCode力扣哈希表篇2

算法学习——LeetCode力扣哈希表篇2 454. 四数相加 II 454. 四数相加 II - 力扣&#xff08;LeetCode&#xff09; 描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 …

Springboot启动出现Waiting for changelog lock...问题

今天在开发的时候&#xff0c;Springboot启动的时候出现Waiting for changelog lock…问题. 问题原因&#xff1a;该问题就是发生了数据库的死锁问题&#xff0c;可能是由于一个杀死的liquibase进程没有释放它对DATABASECHANGELOGLOCK表的锁定&#xff0c;导致服务启动失败&…