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

海东企业网站建设小程序启动失败 错误码

海东企业网站建设,小程序启动失败 错误码,泰安市人才市场,网站缩放代码#x1f431;作者#xff1a;一只大喵咪1201 #x1f431;专栏#xff1a;《网络》 #x1f525;格言#xff1a;你只管努力#xff0c;剩下的交给时间#xff01; 书接上文五种IO模型 | select。 poll | epoll #x1f367;poll#x1f9c1;认识接口#x1f9c1;简… 作者一只大喵咪1201 专栏《网络》 格言你只管努力剩下的交给时间 书接上文五种IO模型 | select。 poll | epoll poll认识接口简易poll服务器poll的特点 epoll认识接口epoll原理简易epoll服务器epoll的特点epoll的工作方式 总结 poll poll也是一种多路转接的方案它专门用来解决select的两个问题 等待fd有上限的问题。每次调用都需要重新设置fd_set的问题。 认识接口 如上图所示便是poll系统调用的声明它有三个参数。 struct pollfd* fds用来设置需要等待的fd以及事件 如上图所示struct pollfd结构体中存在三个成员变量第一个是fd表示需要操作系统等待的文件描述符。第二个是short events表示需要操作系统等待该fd的事件类型。第三个是short revents操作系统告诉用户层该fd的哪个事件就绪了。 此时的文件描述符fd直接设置到struct pollfd结构中即可需要设置哪个就设置哪个不用再去寻找对应的位图。 告诉操作系统需要等待的事件时只需要直接设置short events即可不用将不同的事件类型放在不同的位图中。 当指定文件描述符fd的就绪时操作系统会设置对应short revents用户层直接读取fds中的这个字段便可知道是哪个事件就绪了。 struct pollfd结构体将用户和操作系统设置的字段分开了所以就不存在相互干扰的问题。 events和revents的取值 如上图所示便是用户层以及操作系统可以设置的事件类型这些同样是一些宏定义常用的就是POLLIN数据可读以及POLLOUT数据可写。 假设fds结构体中events的值是POLLIN此时操作系统就关注指定文件描述符的读事件是否就绪如果就绪就将revents的值也设置成POLLIN用户层读取到该值后就知道文件可读了。 nfds_t nfds需要poll等待的文件描述符fd的个数。 如上图所示在内核中nfds_t类型本质上是一个unsigned long int类型也是一个整形。 第二个参数nfds就是用来设定需要poll等待文件描述符的个数的。用户层和操作系统同时维护一个元素为struct pollfd类型的数组这个数组中有多少个元素用户层需要让操作系统等待的文件描述符就有多少个变量nfds就表示数组的大小。 这个数组就类似用户层和操作系统之间的“临界资源”双方都能看到而且都可以访问由于访问的位置不同所以不会出现干扰。 由于nfds的值是由用户层设定的所以poll可同时等待的文件描述符数量并没有上限unsigned long int的最大值非常大远大于一个系统能打开的文件个数所以可以理解为没有上限。 int timeout阻塞等待的时间 和select中的struct timeval变量的作用类似但是这里的timeout是一个int类型的变量它的单位是1ms。并且它不是一个输入输出型参数只需要定义一次即可。 timeout0表示在timout时间以内阻塞等待超出这个时间就超时返回如该值是1000就表示阻塞等待1s。 timeout 0表示非阻塞等待。timeout 0表示阻塞等待。 返回值就绪事件的个数。 和select的返回值意义一样本喵就不再解释了。 简易poll服务器 下面本喵用poll实现一下上面select所实现的服务器大部分代码都一样本喵仅讲解不一样的部分 如上图所示poll服务器中成员变量只是将原本的int* _fdarry类型数组变成了struct pollfd* _rfds类型的数组其他成员保持不变。 initServer()初始化服务器 如上图所示初始化服务器中在堆区开辟的数组变成了struct pollfd类型的数组大小是由户自定义的。 在初始化这个数组的时候需要初始化struct pollfd中的三个字段其中fd仍然是-1revents和events都是0本喵将初始化字段放在了一个函数中。 同样需要将数组中第一个需要等待的文件设置成监听套接字事件设置成POLLIN表示需要操作系统等待监听套接字中的读事件。 Start()启动服务器 如上图所示可以看到此时Start函数比之前简洁了许多因为不用每次轮询的时候都重新设置一遍fd_set了直接调用poll即可然后根据返回值做具体的处理。 同时阻塞事件也不用再重新设置了因为并不是一个输入输出型参数操作系统并不会改变timeout只需要设置一次即可。 HandlerReadEvent()处理事件函数。 如上图所示当事件就绪时仍然需要调用HandlerReadEvent函数来处理事件而且仍然需要遍历数组来判断具体是哪个文件描述符的哪个事件就绪了然后再看是调用Accept还是Recver。 此时遍历判断的时候判断的是struct pollfd中的fd字段之前所有判断fd的语句中都需要变成_rfds[i].fd。在判断是否是POLLIN事件就绪时需要将revents的值与POLLIN进行按位与如果结果大于0则说明该事件就绪了。 其他部分代码本喵就不讲解了因为和select中的代码一样只是遍历判断时由直接的_fdarry[i]变成了_rfds[i].fd包括pollServer.cpp中的代码都不用作任何修改。 如上图服务器运行起来后由于没有新连接到来所以监听套接字每隔5s就超时返回一次。 同样为了避免干扰将poll设置成阻塞等待方式 如上图所示将timeout的值设置成-1表示让poll阻塞等待可以看到运行起来后由于没有新连接到来程序阻塞不动了。 如上图所示使用两个telnet客户端连接客户端后现象和selsect一样也是一个服务端进程可以同时和两个客户端进行通信。 poll的特点 优点 struct pollfd结构包含了要监视的event和发生的revent不再使用select“参数-值”传递的方式接口使用比select更方便。poll并没有最大等待文件描述符数量限制 (但是数量过大后性能也是会下降)。 缺点 和select一样poll返回后需要轮询struct pollfd数组来获取就绪的描述符。每次调用poll都需要把大量的struct pollfd结构从用户层拷贝到内核中。同时连接的大量客户端在一时刻可能只有很少的处于就绪状态因此随着监视的描述符数量的增长, 其效率也会线性下降。 epoll epoll是基于poll的基础上改进的它不仅克服了select的缺点而且解决了poll遍历成本是效率最高的多路转接模式但是它也是最复杂的一种模式。 认识接口 epoll_create 如上图所示的epoll_create系统调用是用来创建epoll句柄的。 int size自Linux2.6.8以后该参数是被忽略的不起实际作用但是必须是大于0的一个值。返回值返回的也是一个文件描述符fd。 epoll句柄在内核中也是一个结构体类似于struct file而Linux下一切皆文件所以返回的也是一个文件描述符拿着这个文件描述符可以访问到这个epoll句柄。 epoll_ctl 如上图所示的epoll_ctl系统调用是用来修改创建的epoll句柄属性的。 int epfd该值就是epoll_create的返回值用来指示哪个epoll句柄。 int op是修改句柄属性的选项有增删改三个选项 EPOLL_CTL_ADD向句柄中增加要等待的文件描述符。 EPOLL_CTL_MOD修改句柄中指定的文件描述符。 EPOLL_CTL_DEL从句柄中删除指定的文件描述符。 int fd要进行操作的文件描述符。 struct epoll_event* event用来指定要等待的事件。 如上图所示便是内核中struct epoll_event结构体的定义它有两个成员变量。 第一个成员是uint32_t events用来设置需要等待的事件其值也是有几个宏组成的集合 值意义EPOLLIN表示对应的文件描述符可以读 (包括对端SOCKET正常关闭)EPOLLOUT表示对应的文件描述符可以写EPOLLPRI表示对应的文件描述符有紧急的数据可读 (这里应该表示有带外数据到来)EPOLLERR表示对应的文件描述符发生错误EPOLLHUP表示对应的文件描述符被挂断EPOLLET将EPOLL设为边缘触发(Edge Triggered)模式, 这是相对于水平触发(Level Triggered)来说的EPOLLONESHOT只监听一次事件, 当监听完这次事件之后, 如果还需要继续监听这个socket的话, 需要再次把这个socket加入到EPOLL队列里 第二个参数是一个联合体epoll_data_t data可以看到有四个成员共用这个联合体后面本喵会讲解它每个变量的妙用。 返回值调用成功返回0调用失败返回-1并且设置相应的错误码。 epoll_wait 如上图所示的epoll_wait系统调用是用来从操作系统中获取被等待文件描述符的状态的。第一个参数不做解释。 struct epoll_event* events是一个数组操作系统将就绪的文件描述符放入这个数组中供用户层读取。 int maxevents该值就是events数组的大小是用户层用来告诉内核这个数组有多大的这个值不能大于epoll_create时的size。 int timeout和poll中是一样的不再解释。 返回值 也是和poll的返回值以及select代表的意义一样大于0表示就绪的文件描述符个数等于0表示超时返回小于0表示调用失败。 以上三个系统调用是epoll模型的核心调用epoll_ctl是用户层用来告诉内核自己的需求的epoll_wait是内核用来告诉用户层哪些文件描述符的什么事件就绪的。 现在知道了接口的使用但是仍然并不清除为什么epoll模型能够解决poll和select存在的问题所以我们需要大概知道epoll模型的底层原理。 epoll原理 网络通信过程中接收端将数据从网卡(硬件层)开始逐层向上交付最后给到应用层那么接收端是如何知道网卡上有数据到来的也就是操作系统是怎么感知到数据来了呢 如上图所示本喵将计算机体系结构冯诺依曼体系结构以及中断向量表放在了一起来讲解。 当网卡接收到数据后输入外设(网卡)会自己产生一个控制信号直接给CPU中的控制器表示此时网卡中有数据到来可以读了。 冯诺依曼体系中外设的数据信号不能直接和CPU传递如上图中红色线条必须经过存储器。外设的控制信号可以直接传递给CPU的控制器如上图黑色线条。 外设给CPU发送一个信号表示数据到来这叫做中断事件发生。 CPU根据中断信号的编号去操作系统维护的中断向量表中找到对应的中断服务函数并且执行。 中断服务函数中会调用网卡接收数据的驱动程序将数据读取并且向上层交付如上图绿色线条所示。 在这里要重点关注中断服务函数从网卡中接收数据是从它开始的。 epoll是一个模型这个模型包含多个数据结构而前面所讲的句柄可以理解为是这个模型标志通过句柄可以找到这个模型并且使用它。 如上图所示是整个epoll模型理论图包含计算机体系结构中的驱动层操作系统系统调用三层。 在调用epoll_create创建模型后会返回一个文件描述符fd这个fd同样放在服务器进程PCB所维护的进程描述符表中通过fd这个句柄就可以找到对应的epoll模型。 epoll模型同样是一个大的结构体只是这个结构体更加复杂在Linux眼中都是struct file所以创建模型后返回的也是一个文件描述符。 上图中操作系统中黑色框内的部分就是epoll模型包含一个红黑树和一个就绪队列。 以增加需要操作系统等待的文件描述符为例调用epoll_ctl将fd以及需要等待的事件构建成struct epoll_event变量插入到红黑树中操作系统会遍历红黑树中所有节点。 红黑树节点中包含很多成员变量如上图左下角所示这其中必然有文件描述符fd需要等待的事件event左右字节的指针。还包括next和prev指针。 如果是删除或者修改等操作同样是在修改这颗红黑树而红黑树查找效率非常高所以对应的操作也会很高效。 当操作系统发现红黑树中有节点的事件就绪后就会将该节点放入到就绪队列中就绪队列是一个双向循环链表。 将节点从红黑树放入到就绪队列中并没有发生拷贝秘密就在next和prev指针上。当网卡中有数据到来时通过中断函数最终调用了网卡驱动程序在驱动程序中有一个回调函数void* private_data这是由操作系统提供的。 private_data回调函数会将红黑树节点中的next和prev指针的指向关系做对应的修改让该节点链入到就绪队列中去。 红黑树的一个节点它不只属于红黑树还可能属于就绪队列。如上图所示红黑树中的节点和就绪队列中的节点地址都是0x11223344。 本喵画的是逻辑图所以将就绪队列和红黑树分开了。 就绪队列中必然也包括就绪文件的文件描述符以及就绪的事件如上图所示的struct epoll_event结构。 所以凡是处于就绪队列中的节点必然已经就绪。 用户层在调用epoll_wait后获取的就是内核中就绪队列中的内容所以获取到的全部都是就绪的事件所以用户层的struct epoll_event类型数组中全部都是就绪的事件。 epoll_wait将所有就绪的事件按照顺序放入到用户层传入的数组中。 此时从内核到用户层虽然也需要遍历但是此时是遍历拷贝而不需要遍历检测所以时间复杂度相当于从之前的O(N)变成了O(1)效率提升的不是一点半点。 简易epoll服务器 和poll服务器一样本喵仅讲解不一样的地方其他和select服务器中有详细讲解。 如上图所示是epoll服务器类的基本组成相比poll服务器有三个变化的成员变量_epfd是epoll模型句柄文件描述符_revs是用户层获取就绪文件描述符的数组_num是该数组的大小。 还包含几个全局的默认值size是调用epoll_create是的参数要大于0并且大于用户层数组的大小。defaultnum是用户层数组的默认大小。 initServer 初始化服务器 如上图所示初始化服务器代码创建epoll模型并且将监听套接字的读事件让操作系统去等待加入到红黑树中最后就是在堆区开辟获取就绪事件所用的数组。 在设置struct epoll_event结构体变量的时候暂时先给data联合体的fd赋值虽然epoll_ctl的第三个参数才是真正指定要等待的文件描述符。 由于用户层在设置的时候设置的是联合体的fd字段所以当该文件的事件就绪时就绪队列中该文件的联合体中仍然是fd字段。 Start 启动服务器 如上图代码所示Start成员函数的实现更加简单仅仅是调用了epoll_wait函数当有事件就绪时调用HandlerReadEvent时需要传入就绪事件的个数方便遍历拷贝。 HandlerReadEvent 如上图所示可以看到此时遍历拷贝的元素全部是已经就绪的事件而不需要再挨个检测所以效率非常高。 Accept 如上图代码所示监听到的新连接同样需要交给操作系统去等待所以需要将新连接的文件描述符添加到红黑树中。 Recver 如上图所示接收数据的代码和之前是一模一样的不同的是当新连接出现异常关闭后需要将新连接的文件描述符从红黑树中删除让操作系统不用再等待该文件描述符了。 epollServer.cpp源文件同样不需要做修改直接用之前的就可以。 如上图运行结果所示epoll模型创建好以后句柄的值是4监听套接字的文件描述符是3两个telnet客户端的连接文件描述符是5和6足以说明该句柄就是一个文件描述符其他效果和之前的一样。 epoll的特点 接口使用方便虽然拆分成了三个函数但是反而使用起来更方便高效不需要每次循环都设置关注的文件描述符也做到了输入输出参数分离开。数据拷贝轻量只在合适的时候调用epoll_ctl将文件描述符结构拷贝到内核中这个操作并不频繁(而select/poll是每次循环都要进行拷贝)。事件回调机制避免使用遍历检测而是使用回调函数的方式将就绪的文件描述符结构加入到就绪队列中。epoll_wait返回直接访问就绪队列就知道哪些文件描述符就绪这个操作时间复杂度是O(1)即使文件描述符数目很多, 效率也不会受到影响。没有数量限制文件描述符数目无上限。 虽然epoll的机制更复杂但是它用起来更方便也更高效。 epoll的工作方式 epoll主要解决的是多路转接中进行IO的时候等的这一环节当操作系统所监管的事件就绪了就会通知用户层来处理事件这个通知有两种方式 水平触发(Level Triggered)工作模式简称LT。边缘触发(Edge Triggered)工作模式简称ET。 来举一个生活中的例子假设你正在打王者荣耀正要推对方水晶的时候你妈喊你吃饭此时就存在两种方式 如果喊你一次你没动那么就会继续喊第二次第三次…直到你去吃饭这种方式就是水平触发。 如果喊你一次你没动之后就不再喊你了这种方式就是边沿触发。 放在多路转接中就是事件就绪时操作系统通知用户层后用户层没有读取数据或者没有读取完毕如果操作系统继续通知就是LT模式如果没有继续通知就是ET模式。 epoll默认状态下就是LT工作模式。LT模式下事件未被用户层处理完毕每调用一次epoll_wait就会返回一个大于0的值。ET模式下事件未被用户处理完毕只有第一次调用epoll_wait才会返回大于0的值之后不再返回并且将事件设置为未就绪状态除非该套接字中数据增加才会再返回一次大于0的值。 在调用epoll_ctl的时候将struct epoll_event中的uint32_t events字段设置成EPOLLET此时该文件描述符就变成了ET模式并没有设置LT模式的方法因为默认就是LT模式。 使用ET模式能够减少epoll触发的次数但是代价就是强逼着程序猿一次响应就绪过程中就把所有的数据都处理完如果不处理完剩下的数据就有可能被覆盖后果由程序猿自己承担。 相当于一个文件描述符就绪之后不会反复被提示就绪所以就比 LT 更高效一些。 ET模式的高效是建立在程序员的痛苦之上的由于它只通知用户层一次如果不一次处理完数据就没机会再处理了但是用户层是怎么知道数据有没有读取完毕呢 答案是循环读取直到读不到数据了就证明读完了。 如上图所示此时就存在一个问题客户端发送了10K的数据给服务端服务端收到了epoll的通知后用户层调用recv进行读取但是一次没有读取完毕只读取了1K的数据。 由于此时epoll是ET模式所以操作系统认为事件已经被处理了就又将读事件设置成了未就绪的状态再次读取时recv就会阻塞不动整个进程就阻塞了如下面伪代码 while(1) {int ret recv(sock,buffer,sizeof(buffer)-1,0);//第二次读取就会阻塞 }由于epoll_wait不会再次返回剩下的9K数据会一直在缓冲区中直到下一次客户端再给服务器写数据操作系统再次将读事件设置成就绪状态才能再次recv。 服务端只有将10k数据完全读取完才会给客户端一个确认应答。 客户端收到服务端的确认应答后才会发送下一个请求。 客户端发送下一个请求epoll_wait才会返回才会将读事件设置未继续服务端才能再次去缓冲区中读取。 服务端无法读取剩余的数据也就不会发出响应客户端无法收到响应也就不会再次发送请求服务端无法收到再次的请求就无法再次读取缓冲区中剩余的数据。 时间一长就会触发TCP的超时重传机制导致数据被覆盖甚至丢失等问题。 为了解决这个问题文件描述符对应的缓冲区必须设置成非阻塞 IO方式本喵在上篇文章中讲解过使用fcntl设置。只有非阻塞方式才能用轮询的方式不断读取缓冲区中的数据直到读取完毕。 如果是LT模式就不用设置成非阻塞模式因为数据没有读取完毕epoll_wait会持续返回而事件也被保持就绪状态recv就可以持续读取数据直到将数据读取完毕。 select和poll是采用LT模式的和epoll的默认方式一样那么如果将文件描述符设置成非阻塞方式仍然使用LT模式不是更方便吗既能循环读取又能让epoll持续返回也能提高效率啊为什么仍然要多此一举设计一个ET模式呢 ET模式的高效不仅仅体现在通知机制上减少通知次数降低系统调用的开销。ET模式的高效还体现在增加底层网络的吞吐量上。 ET模式表面上看是在倒逼程序员将本轮就绪的数据全部读走深入网络底层TCP协议去看服务端由于一次将数据全部读走了从而能给客户端应答一个更大的窗口值。 客户端就能更新出一个更大的滑动窗口增加一次发送的数据量从而提高底层数据发送的效率更好的利用诸如TCP延迟应答等策略提高整个网络通信的吞吐量。 所以说ET模式在压榨程序员的基础上提高了整个网络通信的效率。 总结 虽然介绍了poll和epoll两种方式但是epoll不仅解决了poll方式的问题而且还带来了其他优势比如使用简单遍历成本低等优势以及ET模式对于通信效率的提升虽然epoll的机制更复杂但是它带来了更好的效果利远大于弊。 epoll的高性能是有一定的特定场景的如果场景选择的不适宜epoll的性能可能适得其反。 对于多连接且多连接中只有一部分连接比较活跃时比较适合使用epoll。 例如一个需要处理上万个客户端的服务器例如各种互联网APP的入口服务器这样的服务器就很适合epoll。 如果只是系统内部服务器和服务器之间进行通信只有少数的几个连接这种情况下用epoll就并不合适具体要根据需求和场景特点来决定使用哪种模型。
http://wiki.neutronadmin.com/news/322972/

相关文章:

  • 手机怎么做弹幕小视频网站初中学生做那个的网站
  • 建设网站需要哪些硬件宁波建设网站价格
  • 视频号关键词搜索排名网络营销乐云seo
  • 一般网站要多大空间湖南响应式网站建设
  • 罗阳网站建设wordpress 注册侧边栏
  • 渭南做网站电话淘客返利网站建设
  • 阳狮做网站平台网站怎么建设
  • 做同性恋的珠宝网站怎么用vps做网站
  • 网站制作 语言选择怎么做开发一款app需要多少人
  • 您身边的网站建设顾问哪个网站可以接项目做
  • 六安电商网站建设价格wordpress上长缺少临时文件夹
  • 研发项目备案在哪个网站做seo是什么职位的缩写
  • 外贸网站论文湘潭今天刚刚发生的新闻
  • H5响应式网站数据新冠最新发布会
  • 怎样做视频直播网站电商网名大全
  • 网站获取访客qq号码wordpress mp6
  • 17一起做网站后台建筑工程网线接头规范
  • wordpress 主题不显示图片首页排名关键词优化
  • 马鞍山网站建设制作湛江商城网站开发设计
  • 网站建设 锋云科技在线设计平台代理加盟
  • 旅游网站网页设计在公司的小语种网站上
  • 最新域名网站查询专业制作开发公司网站
  • 电商网站开发源码设计网站页面特效怎么做
  • 烟台网站建设-中国互联门户网站营销策略
  • 创建网站目录时我们应该做网站需要多少空间
  • 合肥制作网站有户型图怎么免费设计装修
  • 建筑施工建设网站从事网页设计工资高吗
  • 网站建站ddp兼职做效果图的网站有哪些
  • 网站建设公司安丘市同信.长春网站建设
  • 在哪学习建网站大连企业建站