zoukankan      html  css  js  c++  java
  • connect socket的超时设置

    最近项目中,有个需求是检测某ip地址是否是通的,使用了socket的connect函数。但是,当ip地址写错的话,connect就会一直阻塞在那里,大概2、3分钟才能返回连接失败。这对于用户来说是不可接受的。下面的文章介绍了两种方法实现这种超时设置:

    转自http://blog.csdn.net/ast_224/article/details/2957294

     connect超时:

    目前各平台通用的设置socket connect超时的办法是通过select(),具体方法如下:

    1.建立socket;
    2.将该socket设置为非阻塞模式;
    3.调用connect();
    4.使用select()检查该socket描述符是否可写;
    5.根据select()返回的结果判断connect()结果;
    6.将socket设回阻塞模式。
        //设socket为非阻塞
        unsigned long ul=1;
        int rm=ioctl(sockfd,FIONBIO,&ul);
        if(rm==-1)
        {
          close(sockfd);
          return 0;  
        }
    
        if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == 0)
        {
         printf("connected/n");//正常连接(小小:使用gdb调试时,从来走不到这一步"设置为非阻塞,connect调用后,无论连接是否建立立即返回-1")
        }
        if(errno!=EINPROGRESS)//若errno不是EINPROGRESS,则出错(EINPROGRESS:以非阻塞的方式来进行连接的时候,返回的结果如果是 -1,这并不代表这次连接发生了错误,如果它的返回结果是 EINPROGRESS,那么就代表连接还在进行中)
        {
         perror("connect");
         printf("cannot connect:%s/n",server);
         return 0;
        }    
        //使用select设置超时
        struct timeval timeout;
        fd_set r;         
        FD_ZERO(&r);
        FD_SET(sockfd,&r);
        timeout.tv_sec=0;   
        timeout.tv_usec=100;
        int retval = select(sockfd+1,NULL,&r,NULL,&timeout);
        if(retval==-1)
        {
          perror("select");
          return 0;
        }
        else if(retval == 0)
        {
          fprintf(stderr,"Timeout/n");
          return 0;
        }
        printf("%sconnected/n",server);
        //将socket设置回正常的阻塞模式
        ul1=0;
        rm=ioctl(sockfd,FIONBIO,(unsigned long*)&ul1);
        if(rm==-1)
        {
          close(sockfd);
          return 0;     
        }

    以上代码工作的很好,并且也可以通过getsockopt()获得连接发生错误的确切信息,但这总方法难免觉得有些复杂,因为要涉及到阻塞状态的解除和回置。

    这里有个简单的操作方法,同样可以设置连接超时:即通过SO_SNDTIMO套节字参数。

    原因是:Linux内核源码中connect的超时参数和SO_SNDTIMO操作的参数一致。

    因此,在linux平台下,可以通过connect之前设置SO_SNDTIMO来达到控制连接超时的目的。

        struct timeval timeo;
        socklen_t len = sizeof(timeo);
        timeo.tv_sec = overtime;
    
    
        if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len) == -1)
        {
            strcpy(reason,strerror(errno));
            perror("setsockopt");
           return 0;
        }
       
        their_addr.sin_family = AF_INET;
        their_addr.sin_port = htons(serverStruct->port);
        their_addr.sin_addr = *((struct in_addr *)he->h_addr);
        bzero(&(their_addr.sin_zero), 8);
     
        if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
        { 
          if (errno == EINPROGRESS)
           {
              strcpy(reason,"timeout");
              return 0;
            }  
           strcpy(reason,strerror(errno));
           perror("connect");
           return 0;
        }  

    小小:上述两种实现方式都可以达到目的。第二种比较简单,利用直接修改connect内部实现用到的参数。但是这种方式可能会产生其他问题吧?(我不确定),可能会影响到其他socket编程接口的超时设定。根据SO_SNDTIMO字面意思来看,是send time out的意思,感觉可能会影响某些发送数据的函数,比如send

  • 相关阅读:
    linux使用secureCRT连接(没有rsa的时候)
    linux删除某个php程序进程的组合命令
    Redis介绍以及安装(Linux)
    PHP Warning: date() [function.date]: It is not safe to rely on the system's timezone
    linux下生成rsa密钥的方法
    mysql 的 infobright 数据库的 mediumblob 显示不了数据
    PHP中的Libevent学习
    PHP函数getopt详解
    php_sapi_name详解
    PHP使用mysqldump备份数据库(以及还原)
  • 原文地址:https://www.cnblogs.com/qxxnxxFight/p/4138465.html
Copyright © 2011-2022 走看看