博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
connect socket的超时设置
阅读量:5359 次
发布时间:2019-06-15

本文共 2603 字,大约阅读时间需要 8 分钟。

最近项目中,有个需求是检测某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

转载于:https://www.cnblogs.com/qxxnxxFight/p/4138465.html

你可能感兴趣的文章
信息收集
查看>>
SQL Server 中使用Convert来取得datetime数据类型样式(全)
查看>>
Python中list的拷贝问题
查看>>
Java学习第二周学习笔记
查看>>
SQL基本语句
查看>>
linux-Centos7安装python3并与python2共存
查看>>
Thread和ThreadPool的应用解析
查看>>
Django部署问题
查看>>
UE4开发神秘海域类游戏原型 初阶(二):动画资源的整合
查看>>
关于二维码的简单使用
查看>>
LeetCode:Regular Expression Matching
查看>>
ToadforDB2_Freeware_6.x 安装报错“Toad did not find a default DB2 client”
查看>>
div 溢出隐藏 div文字溢出用点(省略号)代替
查看>>
关于获取基站信息总结
查看>>
BZOJ.4650.[NOI2016]优秀的拆分(后缀数组 思路)
查看>>
IPMI学习资料
查看>>
CODE[VS] 1497 取余运算
查看>>
5210: 最大连通子块和 动态DP 树链剖分
查看>>
redis 安装 yum install gcc tcl
查看>>
序时薄二次开发(新增按钮)
查看>>