当前位置: 首页 > news >正文

多路转接poll服务器

目录

函数原型

poll服务器

对比select的优点


关于select的详解,可查看多路转接select服务器-CSDN博客

函数原型

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

poll作为多路转接的实现方案,与select要解决的问题是一样的,同时它还要做到规避select的一些缺点

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

这个数据结构中fd告诉了操作系统要关心fd上的事件,events是用户想关心的事件,有POLLIN,

POLLPRI,POLLOUT等等,这些都是宏

#define POLLIN		0x001		/* There is data to read.  */
#define POLLPRI		0x002		/* There is urgent data to read.  */
#define POLLOUT		0x004		/* Writing now will not block.  */

使用时,将events置为0,然后与POLLIN进行算数或运算,就表示告诉操作系统要关心fd的读事件,也可以关心同一个fd的多个事件,比如将events与POLLIN和POLLOUT都或一遍

看到这些宏定义,可以看出events也当成了位图来使用,每个比特位表示某种事件,值为1表示要关心这种事件,为0表示不关心

revents是操作系统返回的事件,表示fd上就绪了的事件,通过将revents与POLLIN进行算数与操作,就可知道写事件是否就绪

可以看出fds参数是一个指针,而后面的nfds参数实际上就是一个整型,这两个参数确定了一个pollfd的数组,pollfd包含了用户要关心哪些文件描述符的哪些事件的信息,还包含了操作系统告诉用户哪些事件就绪的信息。

timeout类似select,表示超时时间,以毫秒为单位

返回值与select一样,返回值为0表示超时返回;为-1表示有错误发生,并设置错误码errno;为正数表示在timeout时间内事件就绪的文件描述符个数

poll服务器

这里只给出poll_server的代码,其他文件的代码对理解poll不重要,只需要了解套接字的使用便可轻松看懂,若要查看其他文件的代码,详见rokobo/wsl_code - Gitee.com

poll服务器与select服务器有很强的相似性,有一个pollfd数组记录需要关心的文件描述符,此外大体思路与select相差不大,看代码可以理解

#include "socket.hpp"
#include "Log.hpp"
#include <poll.h>
#include <memory>
#include <cstring>
#include <cerrno>
#include <vector>
using namespace SocketModule;
using namespace LogModule;
class poll_server
{
public:poll_server():_listen_sock(std::make_shared<TcpSocket>()),_is_running(false),fds(NUM, {-1, 0, 0}){}void init(int port){_listen_sock->BuildTcpSocketMethod(port);fds[0].fd = _listen_sock->Fd();fds[0].events |= POLLIN;}void loop(){_is_running = true;int listenfd = _listen_sock->Fd();int timeout = 2000;while(_is_running){int ret = poll(fds.data(), fds.size(), timeout);if(ret == -1){LOG(LogLevel::ERROR) << "Error message: " << strerror(ret);continue;}else if(ret == 0){LOG(LogLevel::INFO) << "Time out\n";continue;}else{LOG(LogLevel::INFO) << "Dispatch begin\n";dispatcher();}}  }void accepter(int fd){InetAddr client;auto client_sock = _listen_sock->Accepter(&client);if(client_sock == nullptr){LOG(LogLevel::ERROR) << "Accept error";return;}int client_fd = client_sock->Fd();if(client_fd < 0){LOG(LogLevel::ERROR) << "Client fd error";return;}//将client_fd加入到fds中int i=0;for(i=0;i<NUM;++i){if(fds[i].fd == -1){fds[i].fd = client_fd;fds[i].events |= POLLIN;LOG(LogLevel::INFO) << "Accept success: " << client_sock->Fd() << " " << client.Addr();break;}}if(i == NUM){//扩容LOG(LogLevel::ERROR) << "fds is full";fds.resize(NUM * 2, {-1, 0, 0});            return;}}void recver(int who){int fd = fds[who].fd;std::string buffer;auto client_sock = std::make_shared<TcpSocket>(fd);ssize_t ret = client_sock->Recv(&buffer);if(ret == -1){LOG(LogLevel::ERROR) << "Recv error" << strerror(errno);client_sock->Close();//将fd从fds中删除fds[who].fd = -1;fds[who].events = 0;fds[who].revents = 0;return;}else if(ret == 0){LOG(LogLevel::INFO) << "Client closed: " << client_sock->Fd();client_sock->Close();//将fd从fds中删除fds[who].fd = -1;fds[who].events = 0;fds[who].revents = 0;return;}else{LOG(LogLevel::INFO) << "Recv success: " << buffer;return;}}void dispatcher(){//找到所有合法的fd,分发for(int i=0;i<NUM;++i){if(fds[i].fd == -1)continue;if(fds[i].revents & POLLIN){//分发给处理连接的函数if(fds[i].fd == _listen_sock->Fd()){accepter(fds[i].fd);}//分发给处理IO的函数else{recver(i);}}}}void stop(){}
private:std::shared_ptr<TcpSocket> _listen_sock;std::vector<pollfd> fds;bool _is_running;
};

主函数

#include "poll_server.hpp"
#include <string>
int main(int argc, char* argv[])
{if(argc != 2){std::cerr << "Usage: " << argv[0] << " <port>" << std::endl;return -1;}int port = std::stoi(argv[1]);if(port <= 0 || port > 65535){std::cerr << "Invalid port number" << std::endl;return -1;}poll_server s_svr;s_svr.init(port);s_svr.loop();return 0;
}

对比select的优点

poll解决了select关心的文件描述符数量有限的问题,可以向pollfd数组里添加随意添加元素,而且poll将输入参数与输出参数分离,events是输入参数,revents是输出参数,这样不需要像select一样每次调用前都清空,简化了编码

相关文章:

  • 一键配置多用户VNC远程桌面:自动化脚本详解
  • taobao.trades.sold.get(淘宝店铺订单接口)
  • go语言八股文
  • 【Nova UI】七、SASS 全局变量体系:组件库样式开发的坚固基石
  • Vue3集成sass
  • 【gpt生成-其二】以go语言为例,详细讲解 并发模型:线程/协程/ Actor 实现
  • sqoop的参数及初体验
  • RHCE 作业二(密钥登录实验)
  • 香港科技大学广州|先进材料学域金融科技学域博士招生宣讲会—天津大学专场!!!(暨全额奖学金政策)
  • 【LLM】Ollama:容器化并加载本地 GGUF 模型
  • 中国人寿财险广西分公司:金融助推乡村振兴全面发展
  • 如何改电脑网络ip地址完整教程
  • CS61A:SCHEME LIST
  • GitLab 提交权限校验脚本
  • 基于大模型的肛裂手术全流程预测与治疗方案研究报告
  • 部署私有gitlab网站
  • 相对论大师-记录型正负性质BFS/图论-链表/数据结构
  • 极狐GitLab 权限和角色如何设置?
  • 【 React 】重点知识总结 快速上手指南
  • AI智能健康小屋:未来健康管理的前沿阵地
  • 坚守17年,这件事姚明就算赔钱也在继续做
  • 资深翻译家、斯诺研究专家安危逝世,曾为多位外国元首做口译
  • A股三大股指涨跌互现:黄金股再度走强,两市成交10900亿元
  • 广电总局加快布局超高清视听产业链,多项成果亮相
  • 中国戏剧奖梅花奖终评启动在即,17场演出公益票将发售
  • 复旦大学史地学系在北碚