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

网页设计与网站建设百度seo怎么收费

网页设计与网站建设,百度seo怎么收费,租空间做网站,建筑工程网站建设文章目录 1、理解Epoll和对应接口2、简单实现 1、理解Epoll和对应接口 poll依然需要OS去遍历所有fd。一个进程去多个特定的文件中等待#xff0c;只要有一个就绪#xff0c;就使用select/poll系统调用#xff0c;让操作系统把所有文件遍历一遍#xff0c;哪些就绪就加上哪… 文章目录 1、理解Epoll和对应接口2、简单实现 1、理解Epoll和对应接口 poll依然需要OS去遍历所有fd。一个进程去多个特定的文件中等待只要有一个就绪就使用select/poll系统调用让操作系统把所有文件遍历一遍哪些就绪就加上哪些fd再返回。一旦文件太多了遍历效率就显而易见地低。epoll是为处理大批量句柄而作了改进的poll句柄就是访问某种资源时标识这个资源的东西比如C语言中的FILE结构体文件描述符等。不过select/poll并不是没有用处一些老型操作系统并不支持epoll就得使用poll或者select。epoll是在Linux内核2.5.44时引入的到现在为止都是Linux中最高效的多路转接IO方案。 epoll有3个接口。 size是一个被忽略的参数只要大于0就行。如果成功返回一个epoll文件描述符在系统内部创建一些数据结构帮助进行已就绪的fd的管理暂且叫做epoll模型失败返回-1。不用这个epoll文件描述符后要close(epollfd)。 创建后用户要告诉内核应当关心哪个文件描述符上的哪个事件是否就绪select通过一个位图结构fd_set来实现poll通过poll_fd来实现的。另外内核要告诉用户关心的哪些fd上的哪些事件event已经就绪了。epoll还有两个接口去做这两个事。 epfd就是创建函数的返回值op表示想做什么有3个值EPOLL_ADDEPOLL_MODEPOLL_DEL分别是添加、修改、删除fd表示哪一个fdevent表示这个fd上的哪个事件要被关心。 进行等待的接口。返回值和selectpoll接口一样就绪的fd数量timeout的作用和poll一样输入型参数单位是毫秒ms为0表示非阻塞小于0表示阻塞大于0poll在这段时间内阻塞等待如果一直没有事件就绪那么超过时间就返回0中间两个参数是输出型参数操作系统通过这两个告知用户就绪的fd上就绪的事件event。 events是一个32位整数用户输入的是关心的事件返回时操作系统通过这个整数来告诉用户哪些fd的events事件就绪了data的类型是一个联合体通常会使用prt或者fd。events有几种取值 EPOLLIN表示对应的文件描述符可以读 (包括对端SOCKET正常关闭) EPOLLOUT表示对应的文件描述符可以写 EPOLLPRI表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来) EPOLLERR表示对应的文件描述符发生错误 EPOLLHUP表示对应的文件描述符被挂断 EPOLLET将EPOLL设为边缘触发(Edge Triggered)模式这是相对于水平触发(Level Triggered)来说的 EPOLLONESHOT只监听一次事件当监听完这次事件之后如果还需要继续监听这个socket的话需要 再次把这个socket加入到EPOLL队列里 上面的就是宏。这里只关心EPOLLIN和EPOLLOUT。 TCP报头中6个标记位中有一个代表PSH用来提示对方应用层立刻从接收缓冲区读取数据。但PSH并不一定能让应用层读取数据它的催促是让套接字观察的fd对应的文件里的数据处于就绪状态。 操作系统可以把数据从应用层拷贝到缓冲区然后将数据交给网卡。当网卡收到数据后网卡会发送硬件中断操作系统通过查看中断向量表知道发来的中断号是网卡的所以就知道网卡有了数据。select/poll都是在软件层面去检测是否有数据的。 CPU有对应的寄存器寄存器是二进制序列是一种存储单元由硬件电路构成。数据拷贝到CPU的硬件本质是利用高低电频对CPU内的寄存器进行充放电让CPU的寄存器变成和内存一样的值。CPU和所有外设之间都有针脚间接相连。发送中断就像是某个外设产生电流从和它间接相连的针脚向寄存器充电把数据放到寄存器中。之后网卡就可以发送中断号让CPU拷贝数据到内存了。所以数据是可以从外设拷贝到内存的。 用户层往下是系统调用层再往下是操作系统再往下就是传输层及以下了。当用户层创建epoll时OS会维护一个红黑树开始时只有一个根节点并且epoll还会创建一个就绪队列为空。红黑树的节点是结构体里面有fd有事件event整个红黑树就是用户告诉OS要关心哪些fd以及fd上的哪些事件。所以可以看出epoll_ctl本质是对这个红黑树进行增删改比如要删就传对应的fd事件设为nullptr/NULL那就是对红黑树某个节点的删除。fd决定节点是红还是黑左节点还是右节点插入到哪里。内核中一个数据结构对象既可以属于红黑树也可以属于另一个结构。 红黑树上只有某个fd上有对应的事件发生了那么就把这个fd的节点接入到就绪队列中队列只保存已经准备好的fd 对应的event。队列每一个元素也可以是一个结构体只取红黑树中已就绪节点里面的值来填充。epoll_wait接口中间两个参数就是从就绪队列中拿取节点这个接口只看就绪队列可以以时间复杂度为O(1)的方式来检测事件就绪也就是队列是否为空。 节点放入队列实际不是将一个节点内容拷贝到队列节点里而是红黑树节点也是队列节点节点就是一个结构体结构体里可以放入表示已经就绪的事件放入红黑树相关指针信息放入队列相关指针信息建立起队列就是用这个队列相关的指针去指向下一个节点。 当数据就绪时操作系统通过网卡经过网络协议栈拷贝到每个文件的文件缓冲区中。每个节点都有回调机制假设每个文件结构体都有一个变量如果没设置回调就置为空每次操作系统拷贝数据到缓冲区后就去判断一下这个变量为空就退出不为空就调用回调函数回调函数做的工作就是把红黑树上已就绪的节点放到就绪队列中。 红黑树就绪队列回调机制这三个整体就是epoll模型所以epoll_create使用时就是创建了这些从操作系统内部到系统调用形成了一个体系。红黑树就像select/poll中的数组但epoll这里核心的维护交由系统来做不让用户去做。 为什么epoll_create要返回就绪fd的个数以及另外两个接口还需要用这个数字整个机制是由系统做的接口是由进程调用的进程在运行时会创建task_struct指向文件描述符表files_struct表里有一个数组类型是struct file012默认被占用当创建epoll模型操作系统也创建了一个struct file里面有个指针指向epoll模型这个struct file就在调用epoll接口的进程的文件描述符表中。用户进程task_structfiles_structstruct file这是一整个路线。通过epoll_create的返回值也就是另外两个接口的参数epfd两个接口就可以找到进程维护的文件描述符表进而找到struct file然后找到epoll模型就可以对红黑树就绪队列进行操作了。 epoll的红黑树比数组更有效率也不需要底层在线性遍历所有节点上层也不需要遍历节点只需要查看就绪队列用户只需要调用接口就可以操作整个体系。 2、简单实现 Main.cc #include EpollServer.hpp #include memoryint main() {std::unique_ptrEpollServer svr(new EpollServer());svr-InitServer();svr-Start();return 0; }Makefile epollserver:Main.ccg -o $ $^ -stdc11 .PHONY:clean clean:rm -f epollserverEpollServer.hpp中先写基础的 #pragma once#include iostream #include string #include Sock.hpp #include log.hppconst static int gport 8888;class EpollServer { public:EpollServer(uint16_t port gport) : port_(port){}void InitServer(){listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();}void Start(){while(true){sleep(3);}}~EpollServer(){} private:uint16_t port_;Sock listensock_; };现在还不能Accept因为还不知道底层是否有文件就绪如果没有整个服务器就得阻塞了。epoll这里的思路就是把自己的权利交给epoll。要将listensock添加到epoll中不过得先有epoll模型。 创建一个Epoll.hpp #pragma once#include iostream #include string #include sys/epoll.hstatic const int defaultepfd -1;class Epoller { public:Epoller():epfd_(defaultepfd){}~Epoller(){} private:int epfd_; };完善一下Epoll模型并初始化和析构 Epoll.hpp #pragma once#include iostream #include string #include cstdlib #include sys/epoll.h #include err.hpp #include log.hppstatic const int defaultepfd -1; static const int gsize 128;class Epoller { public:Epoller():epfd_(defaultepfd){}void Create(){epfd_ epoll_create(gsize);if(epfd_ 0){logMessage(Fatal, epoll_create error, code: %d, errstring: %s, errno, strerror(errno));exit(EPOLL_CREAT_ERR);//err.hpp里加上这个错误}}int Fd(){return epfd_;}void Close(){if(epfd_ ! defaultepfd) close(epfd_);}~Epoller(){} private:int epfd_; };EpollServer.hpp #pragma once#include Epoll.hpp #include Sock.hpp #include log.hppconst static int gport 8888;class EpollServer { public:EpollServer(uint16_t port gport) : port_(port){}void InitServer(){listensock_.Socket();listensock_.Bind(port_);listensock_.Listen();epoller_.Create();logMessage(Debug, init server success);}void Start(){//1、将listensock添加到epoll中要先有epoll模型while(true){sleep(3);}}~EpollServer(){listensock_.Close();epoller_.Close();} private:uint16_t port_;Sock listensock_;Epoller epoller_; };接下来关注事件。 Epoll.hpp //用户告诉内核要关心哪些事件bool AddEvent(int fd, uint32_t events){struct epoll_event ev;ev.events events;ev.data.fd fd;//fd就是就绪的文件描述符int n epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, ev);if(n 0){logMessage(Fatal, epoll_ctl error, code: %d, errstring: %s, errno, strerror(errno));return false;}return true;}EpollServer.hpp void Start(){//1、将listensock添加到epoll中要先有epoll模型bool r epoller_.AddEvent(listensock_.Fd(), EPOLLIN);//只关心读事件assert(r);//可以做别的判断(void)r;while(true){;}}然后就可以在循环中获取事件了使用wait。从队列里拿数据这个过程是线性拷贝的因为系统不相信用户所以要定义一个struct epoll_event类型的数组来接收。以及wait接口中的events参数里由于拷贝的缘故数据是从左到右连续有效的而返回值 - 1就是当前最后一个有效的下标。 EpollServer.hpp void Start(){//1、将listensock添加到epoll中要先有epoll模型bool r epoller_.AddEvent(listensock_.Fd(), EPOLLIN);//只关心读事件assert(r);//可以做别的判断(void)r;struct epoll_event revs_[gnum];int timeout 1000;while(true){int n epoller_.Wait(revs_, gnum, timeout);switch (n){case 0:logMessage(Debug, timeout...);break;case -1:logMessage(Warning, epoll_wait failed);break;default:logMessage(Debug, 有%d个事件就绪了, n);HandlerEvents(n);//一定有数据就绪break;}}}void HandlerEvents(int num){for(int i 0; i num; i){int fd revs_[i].data.fd;uint32_t events revs_[i].events;logMessage(Debug, 当前正在处理%d上的%s, fd, (eventsEPOLLIN) ? EPOLLIN : OTHER);if(events EPOLLIN)//判断读事件就绪{if (fd listensock_.Fd()){// 1、新连接到来std::string clientip;uint16_t clientport;int sock listensock_.Accept(clientip, clientport);if (sock 0)continue;logMessage(Debug, %s:%d 已经连上服务器了, clientip.c_str(), clientport);// 还不能recv即使有了连接但也不知道有没有数据// 只有epoll知道具体情况所以将sock添加到epoll中bool r epoller_.AddEvent(sock, EPOLLIN);assert(r);(void)r;}else // 2、读事件{char buffer[1024];ssize_t s recv(fd, buffer, sizeof(buffer) - 1, 0);if (s 0){buffer[s - 1] 0;//对打印格式buffer[s - 2] 0;//做一下调整std::string echo buffer;echo [epoll server echo]\r\n;std::cout client# echo std::endl;send(fd, echo.c_str(), echo.size(), 0);}else{if (s 0)logMessage(Info, client quit ...);elselogMessage(Warning, recv error, client quit...);close(fd);//将文件描述符移除//在处理异常的时候fd必须合法才能被处理epoller_.DelEvent(fd);}}}}}Epoll.hpp //用户告诉内核要关心哪些事件bool AddEvent(int fd, uint32_t events){struct epoll_event ev;ev.events events;ev.data.fd fd;//属于用户的数据epoll底层不对该数据做任何修改为了给未来就绪返回int n epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, ev);if(n 0){logMessage(Fatal, epoll_ctl error, code: %d, errstring: %s, errno, strerror(errno));return false;}return true;}bool DelEvent(int fd){return epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, nullptr) 0;}int Wait(struct epoll_event* revs, int num, int timeout){return epoll_wait(epfd_, revs, num, timeout);}读事件处理中我们目前无法读到一个完整的报文。因为完整报文由应用层协议规定我们的代码没有应用层协议所以得自定义一个。 先用回调函数来处理数据 #include functional using func_t std::functionstd::string (std::string);public:EpollServer(func_t func, uint16_t port gport) : func_(func), port_(port){} private:uint16_t port_;Sock listensock_;Epoller epoller_;struct epoll_event revs_[gnum];func_t func_;读事件处理时 else // 2、读事件{char request[1024];ssize_t s recv(fd, request, sizeof(request) - 1, 0);if (s 0){request[s - 1] 0;//对打印格式request[s - 2] 0;//做一下调整std::string response func_(request);send(fd, response.c_str(), response.size(), 0);}else{if (s 0)logMessage(Info, client quit ...);elselogMessage(Warning, recv error, client quit...);close(fd);//将文件描述符移除//在处理异常的时候fd必须合法才能被处理epoller_.DelEvent(fd);}}在Main.cc中传入函数 #include EpollServer.hpp #include memorystd::string echoServer(std::string r) {std::string resp r;resp [echo]\r\n;return resp; }int main() {std::unique_ptrEpollServer svr(new EpollServer(echoServer));svr-InitServer();svr-Start();return 0; }下一篇仍然是Epoll代码。 基本版Epoll 结束。
http://www.pierceye.com/news/111012/

相关文章:

  • 怎么做可以访问网站连接加密东莞++网站建设
  • 企业网站的建设与流程数据分析师要学什么课程
  • 重庆营销型网站随做的好谷歌广告投放教程
  • 个人公众号做网站广州市车管所网站建设
  • 上海网站建设公司排名王也诸葛青cp
  • 常用的设计网站有哪些wordpress如何汉化主题
  • 深圳全网营销型网站免费做调查的网站有哪些
  • 设计素材网站知乎济南seo网站推广
  • 网站建设类岗位杭州国家电网 两学一做 网站
  • html静态网站开发自我介绍网站手机客户端开发教程
  • 营销型网站是什么样的桂林北站有核酸检测点吗
  • 网站未备案被阻断怎么做it培训机构哪个好一点
  • 重庆建设注册执业中心网站网络营销百度百科
  • app网站怎么下载个人备案做视频网站
  • 西宁建一个网站公司广东网站备案
  • 网站数据比较北京网站优化推广公司
  • 想做网站的客户在哪找美间在线设计平台
  • 网站设计规划的目的和要求营销外贸网站建设案例
  • 网站营销力一级a做爰片2017免费网站
  • 昌图网站网页界面设计的要求
  • 做一个网站赚钱什么 门户网站
  • 中国建设银行购物网站帝国织梦wordpress
  • 瑞安网站网站建设松原公司做网站的流程
  • 做网站按页面收费视频解析网站如何做搜索
  • 太原网站的公司赣州安全教育平台
  • 淮北建投网站网站推广与维护有什么不同
  • 深圳网站备案注销平果县免费网站哪家好
  • 如何区分网站开发语言做网站多少钱一般
  • 定制专业app开发seo数据统计分析工具有哪些
  • 某服装公司网站建设论文网站建设seo虾哥网络