北京加密机现场select问题

问题描述

北京项目通过调用我们提供的库libsigxt.a与加密机通信,c/s架构,客户端启用多个线程,每个线程流程有以下三步,连接加密机,签名,关闭链接。在正常运行一段时间后会出现不能连接加密机服务问题。

连接服务器代码如下:

setnonblocking(sk_fd);

ret = connect(sk_fd, (struct sockaddr *)&sa_serv, server_len);
    P_DEBUG("main connect ret:%d\n",ret);
    if(ret < 0){
        if(errno != EINPROGRESS){
            P_DEBUG("mainip connect error ret.\n");
        }else{
            tv.tv_sec = timeout;
            tv.tv_usec = 0;
            fd_set wset;
            FD_ZERO(&wset);
            FD_SET(sk_fd,&wset);
            ret = select(sk_fd+1,NULL,&wset,NULL,&tv);
            printf("main select ret is %d\n",ret);
            if(ret<0){
                P_DEBUG("mainip select error,can not connect to server.\n");
            }else if(ret == 0){
                P_DEBUG("mainip connect timeout.\n");
            }else{
                if(FD_ISSET(sk_fd,&wset)){
                    P_DEBUG("mainip connect successful.\n");
                    setblocking(sk_fd);
                }else{
                    P_DEBUG("not fd_isset(). not connected.\n");
                    goto quit;
                }    
            }
        }
    }

先设置非阻塞模式,然后通过connect连接,当返回0时,表示连接成功;当返回-1,并且errno 为 EINPROGRESS表示正在连接过程中,通过select监听wset,当select返回小于0时,表示连接失败;当select返回0时,表示超时;当返回大于0时,表示连接成功,重新再设置成阻塞模式。

根据现场日志打印,当select返回非1的正数,则监听不到可写事件,连接失败,发送数据也失败。

原因查找定位

通过网上搜索发现,1024限定的不只是监听的个数,还是文件描述符的最大值。FD_SETSIZE限制了文件描述符的个数。
但是根据fd_set存储文件描述符的原理,FD_SETSIZE限制的应该是文件描述符的最大值,当然限制了最大值也就限制了个数。

下面一段摘自man select中的原话
"Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to  or larger than FD_SETSIZE will result in undefined behavior."

再查下现场打开的描述符个数,的确大于1024,造成select返回的结果不可预期。

解决方案

既然select使用除了问题,那就换成epoll来监听,修改代码如下:

setnonblocking(sk_fd);

        ret = connect(sk_fd, (struct sockaddr *)&sa_serv, server_len);
        if(ret == 0){
            goto connect_success;
        }
        
        if(ret<0 && errno != EINPROGRESS){
            P_DEBUG("back connect failed.\n");
            goto connect_failure;    
        }

        if((epfd = epoll_create(1))<0){
            P_DEBUG("main epoll create error.\n");
            goto connect_failure;
        }
        memset(&ev, 0, sizeof ev);
        ev.events = EPOLLOUT;
        ev.data.fd = sk_fd;

        if(epoll_ctl(epfd, EPOLL_CTL_ADD, sk_fd, &ev)<0){
            P_DEBUG("main epoll_ctl error.\n");
            goto connect_failure;
        }
        
        n = epoll_wait(epfd,events,1,itimeout);
        P_DEBUG("back epoll_wait n is %d\n",n);
        if(n<=0 || events[0].events & EPOLLERR){
            P_DEBUG("back connect failure.\n");
            goto connect_failure;
        }
     

connect_success:
    
    P_DEBUG("connect success.\n");
    setblocking(sk_fd);

   ......

connect_failure:
    if(sk_fd>0)
        close(sk_fd);
    sk_fd = -1;
    if(epfd>0)
        close(epfd);
    return -1;

}

经测试发现,没有再出现连接失败问题。

结论:建议linux下弃用select。

       
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值