zoukankan      html  css  js  c++  java
  • 我用select做多路复用踩到的坑

    既然说是用select踩到的坑,那么就先直接贴一段使用select的代码上来瞅一下:
        bool SocketAction(int fd, const char* buf, size_t len, uint64_t milli_expire) {
            struct timeval tv;
            tv.tv_sec = milli_expire / 1000;
            tv.tv_usec = (milli_expire % 1000) * 1000;
            fd_set rd_set, wt_set;
            FD_ZERO(&rd_set);
            FD_ZERO(&wt_set);
            FD_SET(fd, &rd_set);
            FD_SET(fd, &wt_set);
    
            int ret = 0;
            while (true) {
                ret = select(fd+1, &rd_set, &wt_set, nullptr, &tv);
                if (ret < 0 && errno == EINTR) continue;
                break;
            }
    
            if(FD_ISSET(fd, &rd_set)) {
    			char rd_buf[1024] = {0};
    			ret = read(fd, rd_buf, sizeof(rd_buf));
    			if(ret < 0)	return false;
    			printf("%s
    ", rd_buf);
    		} else if(FD_ISSET(fd, &wt_set)) {
    			ret = send(fd, buf, len, 0);
    			if(ret < 0) return false;
    		}
    
            return true;
        }

    上面的代码着实非常easy,仅仅是针对某一个socket fd进行读写操作,从逻辑上来说应该是没有不论什么问题的。然而这个在实际的使用过程中确实会出现故障。我们程序中封装了socket的操作,如上代码的方式使用了select。

    在出现大量的socket连接时,会出现宕机现象,而且宕机生成的core文件的堆栈也莫名其妙的被破坏了。

    遇到这个情况时。我直接被震惊了,由于细致检查了代码确实没有发现不论什么问题。为什么每次都是连接数达到快1500的时候就出现宕机呢?

    刚開始以为是其它的逻辑出了问题。于是细致检查了其它的逻辑确实也没有发现存在不论什么问题,而且从堆栈被破坏的情况上分析,也怀疑是某个使用中出现了数组越界訪问引发的。但在整个逻辑中使用的都是stl里的容器,没有申请数组,出现读写越界着实无法理解。

    此后仅仅能怀疑底层封装的问题。在一步步尝试凝视代码的过程中。发现select使用的地方出现了问题。那么问题到底在哪里呢?

     int select(int nfds, fd_set *readfds, fd_set *writefds,
                      fd_set *exceptfds, struct timeval *timeout);


     nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

    在select的使用manual中,select的定义和nfds的说明如上所看到的。也仅仅是说明了select的nfds是最大的文件描写叙述符+1。在实际的使用过程中也确实有这么使用。好像也确实没有问题。然而,不止这么简单。select的文件描写叙述符的最大值实际是有一个潜在规则的。那就是select的最大文件描写叙述符最大是1024。该值在centor os系统中。定义在文件/usr/include/sys/select.h文件里。例如以下:

       78 /* Maximum number of file descriptors in `fd_set'.  */
       79 #define FD_SETSIZE      __FD_SETSIZE

    而__FD_SETSIZE则定义在:/usr/include/bits/typesizes.h 中,例如以下:

       62 /* Number of descriptors that can fit in an `fd_set'.  */
       63 #define __FD_SETSIZE        1024      

    这下能够理解了吧。在socket大于1024时。文件描写叙述符自然就大于1024,则在使用select时訪问的大小就实际超越了系统中对于select的支持。因此出现读写越界,造成程序的宕机。

    这次所踩的坑很隐晦,但也说明了一个问题。在使用系统接口时须要谨慎。尽管可能用法并没有错误,但也要在使用的时候多注意其“潜规则”。

  • 相关阅读:
    Java中的基本数据类型以及自增特性总结
    mysql菜鸟
    Typora使用教程
    net core下链路追踪skywalking安装和简单使用
    netcore5下ocelot网关简单使用
    netcore热插拔dll
    快速排序
    netcore5下js请求跨域
    SpringBoot接口防刷
    EL 表达式
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7237729.html
Copyright © 2011-2022 走看看