(P4)poll

1.poll使用的基本流程

  • epoll的LT电平触发模式与poll模型(就是电平触发模式)的用法是完全一模一样的。要记住!
    (P4)poll

  • (P3)poll:poll函数原型中的例子03\echosrv_poll.cpp是玩具代码,why?
    (1)如果应用层发过来的数据包,刚好分包了,即:一个数据包,两次read(粘包问题),第一次read时并不是一个完整的客户端请求,该怎么办呢?
    对于每一个connfd分配一个应用层缓冲区,我们应该将读到的数据保存在connfd的应用层接收缓冲区,将每次读到的数据追加到应用层缓冲区的末尾。
    如何解析协议?让解析协议去应用层缓冲区去读取数据,判断它是否为一条完整的消息,然后对消息进行处理。
    (2)假设应答的数据量比较大,假如10000字节,write的时候实际上只发送了1000字节,因为内核发送缓冲区有可能满了,该缓冲区满了,write系统调用不会阻塞,因为connfd是非阻塞的fd(connfd = accept4(listenfd, (struct sockaddr*)&peeraddr, &peerlen, SOCK_NONBLOCK | SOCK_CLOEXEC);),如果设置成阻塞模式,会把线程阻塞住了,其他的fd产生了事件就没办法处理了,会降低并发服务器效率,所以要用非阻塞的fd!!!

  • 当发送缓冲区满了,write不能把所有的数据都发送出去,我们也应该有一个应用层的发送缓冲区。

  • 什么时候产生可写事件,即POLLOUT事件?
    POLLOUT事件的触发条件:connfd内核中的发送缓冲区不满时(可以容纳事件了),就把应用层的缓冲区拷贝到内核中的缓冲区当中。
    不能一接收到connfd事件的时候就关注POLLOUT事件,如果一开始就关注,刚开始的时候,发送缓冲区不是满的,但是又没有发送数据,它会一直触发POLLOUT事件,则会出现忙等待busy-loop。所以,应该在内核缓冲区已经满了,才关注它的POLLOUT事件,随着内核缓冲区的数据发送出去,被对等方接收走,发送缓冲区的数据就会被移除,就会腾出空间接受更多的数据,此时POLLOUT事件就发生了,再poll一遍检测到事件,在处理已连接套接字事件的时候,遍历已连接套接字集,就有可能遍历到connfd POLLOUT事件的到来,此时取出应用层缓冲区的数据进行发送,如果这次还没发送完,那么POLLOUT事件就不能取消关注

  • 此外,还要考虑应用层的接收缓冲区InputBuf

2.EMFILE处理

  • accept(2)返回EMFILE(太多的文件)的处理的解决的方法:
    (1)调高进程文件描述符数目,但是系统资源有限,不好
    (2)死等,等待服务端关闭socket,就能腾出一个fd,不好
    (3)退出程序,不好不能满足7*24h服务,不好
    (4)关闭监听套接字。那什么时候重新打开呢?
    (5)如果是epoll模型,可以改用edge trigger。问题是如果漏掉了一次accept(2),程序再也不会收到新连接。
    (6)准备一个空闲的文件描述符。遇到这种情况,先关闭这个空闲文件,获得一个文件描述符名额;再accept(2)拿到socket连接的文件描述符;随后立刻close(2),这样就优雅地断开了与客户端的连接;最后重新打开空闲文件,把“坑”填上,以备再次出现这种情况时使用。

  • eg:2.EMFILE处理中(6)处理方式

22:49