• 服务端使用IO多路复用(select,poll等)时, 为什么监听套接字不能是阻塞IO的?


    预备知识

    RST

    if (FD_ISSET(listen_fd, &readset)) { // 监听套接字上触发事件,说明有连接建立完成,此时调用 accept 肯定可以返回已连接套接字。这样看来,似乎把监听套接字设置为非阻塞,没有任何好处。
    printf("listening socket readable
    ");    
    sleep(5); // 在这5秒期间,已完成连接的套接字(已连接套接字),因为对方发送RST使得本服务端删除掉该连接。
    struct sockaddr_storage ss;    
    socklen_t slen = sizeof(ss);    
    int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); // 没有创建好的连接,此时accep会一直阻塞,直到有新的连接建立好。
    // 更为严重的是,该线程再也没有机会对其他 I/O 事件进行分发,相当于该服务器无法对新连接和其他 I/O 进行服务。// TODO 有的问题
    

    Q: 如果accept传入的监听套接字listen_fd是非阻塞IO的,那么accept就不会阻塞总是会返回值吗?

     int fd = accept(listen_fd, (struct sockaddr *) &ss, &slen); // 如果listen_fd是非阻塞IO的套接字,accept是不是就不会阻塞,但是会多几种返回值?
    

    A: 应该是总是能返回,但是会返回异常值,需要忽略掉。
    A:
    所以解决的办法就是把监听套接字设为非阻塞,再用accept配合IO复用。
    然后对于accept的返回值,忽略EWOULDBLOCK(BSD中的客户终止连接)、EAGAIN、ECONNABORTED(POSIX实现中的客户终止连接)、EPROTO(SVR4中的客户终止连接)、EINTR(被信号中断)。// 附录2

    可能阻塞的套接字调用可分为以下四类

    // 附录3
    套接字的默认状态是阻塞的,这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待响应操作完成,可能阻塞的套接字调用可分为以下四类:
    (1) 输入操作,包括read,readv,recv,recvfrom,recvmsg;
    (2) 输出操作,包括write,writev,send,sendto,sendmsg;
    (3) 接受外来连接,即accept函数。
    (4) 发起外出连接,即tcp的connect函数;

    参考

    1. https://time.geekbang.org/column/article/141573
    2. 非阻塞TCP套接字的要点
    3. TCP之非阻塞connect和accept
  • 相关阅读:
    C# 编译机器码过程原理之再谈反射
    百度Echarts中国地图经纬度
    网页客服思路以及QQ截图粘贴到聊天框功能
    Linux查看CPU和内存使用情况
    Java 打包方式
    电商系统 常用代码 MyBatis-Plus
    Java cnpm install 没有反应
    Java 项目无法运行 解决
    电商系统 常用代码 VUE
    电商系统 常用代码段 Element-ui
  • 原文地址:https://www.cnblogs.com/yudidi/p/12661893.html
Copyright © 2020-2023  润新知