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

天津市网站建设+网页制作微信crm

天津市网站建设+网页制作,微信crm,网站流量与广告费,让百度收录网站前言:本节内容主要讲述多路转接的Poll, 这是我们讲解的多路转接中的第二个解决方案。 Poll主要由select修改而来, 没有select和后面的Epoll重要, 但是友友们还是要认真学习哦!现在废话不多说,开始我们的学习…

        前言:本节内容主要讲述多路转接的Poll, 这是我们讲解的多路转接中的第二个解决方案。 Poll主要由select修改而来, 没有select和后面的Epoll重要, 但是友友们还是要认真学习哦!现在废话不多说,开始我们的学习吧!

        ps:本节内容之前最好看一下select的知识点哦!

目录

POLL 

Poll相较于Select的优点

Pollfd

POLL代码实现

准备文件

Poll_server.hpp

初始化

Start


POLL 

Poll相较于Select的优点

        其实, select是有一些缺点的。 这些缺点导致当select等待的就绪的文件描述符越来越多时, 其实效率不会一直提高下去, 是一定会有一个临界点的。 下面就是select的一些缺点:

  •         1.等待的fd是有上限的。(因为它是使用位图的方式将要关心的文件描述符交给内核。并且位图对应的类型也是固定的。所以select就势必等待的fd是有上限的)
  •         2.输入输出型参数比较多,数据拷贝的频率比较高.
  •         3. 输入输出型参数比较多,每一次都要对关心的fd事件进行重置.
  •         4、使用第三方数组管理用户的fd,用户层需要很多次遍历。内核中检测fd事件就绪,也要遍历.

         为了修正select的问题,就有了下一种解决方案: poll。

        poll只负责等待,在select的基础上,解决select的两个硬伤:等待fd有上限的问题和输入输出型参数比较多,每次都要对关心的fd进行事件重置的问题。首先返回值,大于零代表有几个文件描述符就绪,等于零代表超时了,小于零代表失败。

        第三个参数使用的timeout整形,单位是毫秒。设为1000,就是1秒timeout一次。

        重要的是第一个参数,是结构体。第二个参数是nfds_t。pollfd我们可以理解为一个数组,第二个参数可以理解为这个数组中一共有多少个元素。

Pollfd

        这个结构体的意思就是,当我们用户向内核交付的时候,就是关心fd的events这个事件。 返回的时候,内核就告诉用户,fd的revents这个事件就绪了。

        所以, pollfd将输入和输出事件进行了分离。所以,未来要关心多个文件描述符,就传过去多个包含文件描述符的pollfd对象的数组就可以了。以后只需要利用nfds遍历pollfd,检测哪些就绪。

        这里的short类型如何表示事件,其实就是位图的原理,利用比特位进行标记。对应比特位代表不同的事件,下面是对应事件的宏:

事件

描述可作为输入?可作为输出?
POLLIN数据(包括普通数据和优先数据)可读
POLLRDNORN普通数据可读

POLLRDBAND优先级带数据可读是  
POLLPRI高优先级数据可读,比如TCP带外数据
POLLOUT数据(包括普通数据和优先数据)可写
POLLWRNORM普通数据可写
POLLWRBAND优先级带数据可写是       
POLLRDHUPTCP连接被对方关闭, 或者对方关闭了写操作。它由GNU引入
POLLERR错误
POLLHUP挂起。比如管道的写端被关闭后, 读端描述符上将收到POLLHUP事件
POLLNYAL文件描述符没有打开

POLL代码实现

准备文件

Poll的文件类似于Select:

由于上一节已经介绍了相关文件, 所以本节不再赘述。 

Poll_server.hpp

先看整体类定义:

#pragma once
#include <iostream>
using namespace std;
#include "Log.hpp"
#include "Socket.hpp"
#include<poll.h>
#include <sys/time.h>
//以上,需要用到的头文件int defaultport = 8080;  //设置默认端口号
static const int fd_num_max = 64; // 设置最大fd的个数默认值
int defaultfd = -1                // 辅助数组默认初始值
int non_event = 0;                //一开始没有事件的时候默认设置成零class PollServer
{
public:PollServer{}~PollServer(){}bool Init(){}//void Accepter(){}void Recver(int fd, int i){}//void Dispatcher(){}//void Start(){}void PrintFd(){}private:Socket listensock_;uint16_t port_;pollfd _event_fds[fd_num_max];   //这里可以使用vector// int fd_array[fd_num_max];
};

        一共有三个成员变量, 一个listensock_用来监听新连接。 一个port_设置端口号。 一个_event_fds就是我们关心的fd。是pollfd类型的。

初始化

        初始化, 先将pollfd数组里面都设置成默认值, 利用定义的全局变量defaultfd和non_event设置。然后启动服务器开始监听。

    PollServer(uint16_t port = defaultport): port_(port){// 初始化pollfd数组for (int i = 0; i < fd_num_max; i++){_event_fds[i].fd = defaultfd;_event_fds[i].events = non_event;_event_fds[i].revents = non_event;// cout << "fd_array[" << i << "]" << " : " << fd_array[i] << endl;}}~PollServer(){listensock_.Close();}bool Init(){listensock_.InitSocket();listensock_.Bind(port_);listensock_.Listen();return true;}

Start

        服务器运行的时候, 就是循环式的检查_event_fds数组里面有没有需要关心的fd事件就绪了。 如果有, 那么就进入Dispatcher进行事件派发。如下为Start:

    void Start(){_event_fds[0].fd = listensock_.Fd();_event_fds[0].events = POLLIN;//新连接到来,事件类型等于读事件就绪。 所以这里设置成POLLIN, 表示读事件就绪。int timeout = 3000;for (;;){int n = poll(_event_fds, fd_num_max, timeout);  //第一个数组元素, 第二个数组元素个数switch (n){case 0:cout << "time out, timeout: " << endl;break;case -1:cerr << "poll error" << endl;break;default:// 有时间就绪了,TOODcout << "get a link!!!" << endl;Dispatcher(); //事件派发break;}}}

        事件派发就是因为有事件就绪, 但是我们并不能直接定位数组中哪个元素的fd就绪了, 所以就要循环检测。 如果检测的时候检测到fd的revents是POLLIN, 就是就绪了。 那么就可以根据不同情况分发不同事件了。 有两种情况:一种是fd和监听fd相同,说明来了新连接。 就要进入连接管理器。 另一种就是来信息了, 读取就行了。 

    void Dispatcher(){for (int i = 0; i < fd_num_max; i++){   int fd = _event_fds[i].fd;  //得到合法文件描述符if (fd == defaultfd) continue;  //这个文件描述符不关心//然后根据rfds判断是否fd就绪if (_event_fds[i].revents & POLLIN)   //判断就绪{if (fd == listensock_.Fd())   //如果fd就是当前listensock_的fd, 说明有新连接岛链, 就链接。{Accepter();    //链接管理器}else{Recver(fd, i);  //读取管理器}}}}

        连接管理器进行的操作分两步。 第一步:连接。第二步:将fd封装成pollfd类型对象加入到_event_fds数组中。 下面就是这个流程:

    void Accepter(){string clientip;uint16_t clientport = 0;int sock = listensock_.Accept(&clientip, &clientport);   //此时不会阻塞在这里, 因为新连接到来了我们才accept, 而不是先accept等待新连接到来。if (sock < 0) return;lg(Info, "accept success, %s: %d, sock fd : %d", clientip.c_str(), clientport, sock);   //链接成功//链接成功之后, 就是添加新需要关心的fd进入数组中。int pos = 1;for (;pos < fd_num_max; pos++){if (_event_fds[pos].fd != defaultfd) continue;else break;}if (pos == fd_num_max)   //如果这个条件成立, 就说明pos加到了fd_num_max,而不是遇到了defaultfd。 就说明满了, 就把监听sock关掉。 {lg(Waring, "server is full, close %d now!", sock);close(sock);        //这里可以扩容}else   //遇到了defaultfd, 没满{_event_fds[pos].fd = sock;    //将defaultfd的位置设置为新连接的fd。_event_fds[pos].events = POLLIN;_event_fds[pos].revents = non_event;PrintFd();}}

        读取管理器就是读取接收缓冲区里面的内容即可。

    void Recver(int fd, int i){char buffer[1024];ssize_t n = read(fd, buffer, sizeof(buffer) - 1); if (n > 0){buffer[n] = 0;cout << "get a message: " << buffer << endl;}else if (n == 0)  //等待超时,{lg(Info, "client quit, me too, close fd is : %d", fd);close(fd);_event_fds[i].fd = defaultfd;}else{lg(Waring, "recv error: fd is : %d", fd);   close(fd);_event_fds[i].fd = defaultfd;}}

——————以上就是本节全部内容哦, 如果对友友们有帮助的话可以关注博主, 方便学习更多知识哦!!!

http://www.dtcms.com/wzjs/385948.html

相关文章:

  • 广西南宁网站建设哪家好推广产品最好的方式
  • 可信网站验证服务证书重大军事新闻
  • asp网站 并发数开源seo软件
  • 亳州网站网站建设网站推广方式
  • 做网站英语老师的简历教育培训机构
  • wordpress插入备案seo具体seo怎么优化
  • 网站访客qq获取原理最新热搜新闻
  • 哪个网站收录排名好外国搜索引擎登录入口
  • 网站设计导航栏怎么做徐州关键词优化排名
  • 999免费的网站百度竞价在哪里开户
  • 网站备案在哪里查询现在什么app引流效果好
  • wordpress 查看文章404天津百度seo
  • 杭州网站建设app福州seo服务
  • 福州营销型网站建设价格宁波抖音seo搜索优化软件
  • 8元一年虚拟云主机seo推广软件排行榜
  • 360提交网站备案合肥网站制作公司
  • 淘宝做代销在哪个网站上进货比较好app优化
  • 福田网站建设龙岗网站建设罗湖网站建设百度官网认证入口
  • 学做衣服的网站有哪些病毒式营销的案例
  • 政务网站信息化建设情况汇报平台推广网站
  • 织梦网站图片无缝滚动怎么做小广告图片
  • 做电影网站怎么降低内存竞价推广账户竞价托管公司
  • 费用网站建设域名查询服务器
  • 西安建设银行工作招聘网站比较好的友链平台
  • 临清网站建设郑州百度推广外包
  • 深圳响应式网站建设公司关键词排名优化官网
  • 装修网站cms百度推广代理加盟
  • 微信推广网站怎么做宝鸡网站开发公司
  • 嘉兴网站建设方案咨询网站片区
  • 网站上的视频上传怎么做企业宣传推广