当前位置: 首页 > 编程日记 > 正文

非阻塞socket的连接

引用自:http://blog.csdn.net/cccallen/article/details/6619994

连接套接字,阻塞的套接字超时时间很长无法接受,而是用非阻塞套接字时使用的方案也有多种。后者是个比较好的方法 
方案1:不断重试,直到连接上或者超时:

[cpp] view plaincopy
  1. int connect_socket_timeout(int sockfd,char *dest_host, int port, int timeout)
  2. {
  3. struct sockaddr_in address;
  4. struct in_addr inaddr;
  5. struct hostent *host;
  6. int  err, noblock=1 , connect_ok=0, begin_time=time(NULL);
  7. log_debug("connect_socket to %s:%dn",dest_host,port);
  8. if (inet_aton(dest_host, &inaddr))
  9. {
  10. log_debug("inet_aton ok now gethostbyaddr %sn",dest_host);
  11. memcpy(&address.sin_addr, &inaddr, sizeof(address.sin_addr));
  12. }
  13. else
  14. {
  15. log_debug("inet_aton fail now gethostbyname %s n",dest_host);
  16. host = gethostbyname(dest_host);
  17. if (!host) {
  18. /* We can't find an IP number */
  19. log_error("error looking up host  %s : %dn",dest_host,errno);
  20. return -1;
  21. }
  22. memcpy(&address.sin_addr, host->h_addr_list[0], sizeof(address.sin_addr));
  23. }
  24. address.sin_family = AF_INET;
  25. address.sin_port = htons(port);
  26. /* Take the first IP address associated with this hostname */
  27. ioctl(sockfd,FIONBIO,&noblock);
  28. /** connect until timeout */
  29. /*
  30.   EINPROGRESS   A nonblocking socket connection cannot be completed immediately.
  31.   EALREADY     The socket is nonblocking and a  previous connection attempt has not been completed.
  32.   EISCONN      The socket is already connected.
  33.   */
  34. if (connect(sockfd, (struct sockaddr *) &address, sizeof(address)) < 0)
  35. {
  36. err = errno;
  37. if (err != EINPROGRESS)
  38. {
  39. log_error("connect = %d connecting to host %sn", err,dest_host);
  40. }
  41. else
  42. {
  43. //                                log_notice("connect pending, return %d n", err);
  44. while (1) /* is noblocking connect, check it until ok or timeout */
  45. {
  46. connect(sockfd, (struct sockaddr *) &address, sizeof(address));
  47. err = errno;
  48. switch (err)
  49. {
  50. case EISCONN:   /* connect ok */
  51. connect_ok = 1;
  52. break;
  53. case EALREADY:  /* is connecting, need to check again */
  54. //log_info("connect again return EALREADY check again...n");
  55. usleep(50000);
  56. break;
  57. default:   /* failed, retry again ? */
  58. log_error("connect fail err=%d n",err);
  59. connect_ok = -1;
  60. break;
  61. }
  62. if (connect_ok==1)
  63. {
  64. //log_info ("connect ok try time =%d n", (time(NULL) - begin_time) );
  65. break;
  66. }
  67. if (connect_ok==-1)
  68. {
  69. log_notice ("connect failed try time =%d n", (time(NULL) - begin_time) );
  70. }
  71. if ( (timeout>0) && ((time(NULL) - begin_time)>timeout) )
  72. {
  73. log_notice("connect failed, timeout %d secondsn", (time(NULL) - begin_time));
  74. break;
  75. }
  76. }
  77. }
  78. }
  79. else        /* Connect successful immediately        */
  80. {
  81. // log_info("connect immediate success to host %sn", dest_host);
  82. connect_ok = 1;
  83. }
  84. /** end of try connect */
  85. return ((connect_ok==1)?sockfd:-1);
  86. }

 

方案2:
  补充关于select在异步(非阻塞)connect中的应用,刚开始搞socket编程的时候我一直都用阻塞式的connect,非阻塞connect的问题是由于当时搞proxy scan
  而提出的呵呵,通过在网上与网友们的交流及查找相关FAQ,总算知道了怎么解决这一问题.同样用select可以很好地解决这一问题.大致过程是这样的:
  1.将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完成(有的系统用FNEDLAY也可).
  2.发connect调用,这时返回-1,但是errno被设为EINPROGRESS,意即connect仍旧在进行还没有完成.
  3.将打开的socket设进被监视的可写(注意不是可读)文件集合用select进行监视,如果可写,用getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, sizeof(int));
  来得到error的值,如果为零,则connect成功.
  在许多unix版本的proxyscan程序你都可以看到类似的过程,另外在solaris精华区->编程技巧中有一个通用的带超时参数的connect模块.
   我们知道,缺省状态下的套接字都是阻塞方式的,这意味着一个套接口的调用不能立即完成时,进程将进入睡眠状态,并等待操作完成。对于某些应用,需要及时 可控的客户响应,而阻塞的方式可能会导致一个较长的时间段内,连接没有响应。造成套接字阻塞的操作主要有recv, send, accept, connect.
  下面主要以connect为例,讲讲非阻塞的connect的工作原理。当一个TCP套接字设置为非阻塞后,调用 connect,会立刻返回一个EINPROCESS的错误。但TCP的三路握手继续进行,我们将用select函数检查这个连接是否建立成功。建立非阻 塞的connect有下面三个用途:
  1.可以在系统做三路握手的时候做些其它事情,这段时间你可以为所欲为。
  2 可以用这个技术同时建立多个连接,在web应用中很普遍。
  3.可以缩短connect的超时时间,多数实现中,connect的超时在75秒到几分钟之间,累傻小子呢?
  虽然非阻塞的conncet实现起来并不复杂,但我们必须注意以下的细节:
  * 即使套接字是非阻塞的,如果连接的服务器是在同一台主机,connect通常会立刻建立。(connect 返回 0 而不是 EINPROCESS)
  * 当连接成功建立时,描述字变成可写
  * 当连接出错时,描述字变成可读可写

 

[cpp] view plaincopy
  1. int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec)
  2. {
  3. int flags, n, error;
  4. socklen_t len;
  5. fd_set rset, wset;
  6. struct timeval tval;
  7. // 获取当前socket的属性, 并设置 noblocking 属性
  8. flags = fcntl(sockfd, F_GETFL, 0);
  9. fcntl(sockfd, F_SETFL, flags | O_NOBLOCK);
  10. errno = 0;
  11. if ( (n = connect(sockfd, saptr, salen)) < 0)
  12. if (errno != EINPROGRESS)
  13. return (-1);
  14. // 可以做任何其它的操作
  15. if (n == 0)
  16. goto done; // 一般是同一台主机调用,会返回 0
  17. FD_ZERO(&rset);
  18. FD_SET(sockfd, &rset);
  19. wset = rset;  // 这里会做 block copy
  20. tval.tv_sec = nsec;
  21. tval.tv_usec = 0;
  22. // 如果nsec 为0,将使用缺省的超时时间,即其结构指针为 NULL
  23. // 如果tval结构中的时间为0,表示不做任何等待,立刻返回
  24. if ((n = select(sockfd+1, &rset, &west, NULL,nsec ?tval:NULL)) == 0) {
  25. close(sockfd);
  26. errno = ETIMEOUT;
  27. return (-1);
  28. }
  29. if(FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &west)) {
  30. len = sizeof(error);
  31. // 如果连接成功,此调用返回 0
  32. if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
  33. return (-1);
  34. }
  35. else
  36. err_quit(“select error: sockfd  not set”);
  37. done:
  38. fcntl(sockfd, F_SETFL, flags); // 恢复socket 属性
  39. if (error) {
  40. close(sockfd);
  41. errno = error;
  42. return (-1);
  43. }
  44. return (0);
  45. }

现在在网络服务器编程中使用epoll比较普遍,创建一个socket,设为异步socket(fcntl)

connect到远端(此时connect调用返回非0,但errno为EINPROGRESS,表示正在建立连接中)

由epoll负责监听fd的状态,epoll_wait之捕获到EPOLLOUT事件,收到EPOLLOUT也不能认为是

TCP层次上connect(2)已经成功,要调用getsockopt看SOL_SOCKET的SO_ERROR是否为0。若为0,

才表明真正的TCP层次上connect成功。至于应用层次的server是否收/发数据,那是另一回事了。

转载于:https://www.cnblogs.com/langqi250/archive/2012/12/04/2801407.html

相关文章:

OpenCV下车牌定位算法实现代码

转自&#xff1a;http://blog.csdn.net/heihei723/archive/2006/05/14/728046.aspx#FeedBack 车牌定位算法在车牌识别技术中占有很重要地位&#xff0c;一个车牌识别系统的识别率往往取决于车牌定位的成功率及准确度。 车牌定位有很多种算法&#xff0c;从最简单的来&#xff0…

2018-2019-1 20165310 20165315 20165226 实验一 开发环境的熟悉

2018-2019-1 20165226 20165310 20165315 实验一 开发环境的熟悉 目录 一、实验目的 二、实验步骤 三、实验过程中遇到的问题及解决 四、实验感想 一、实验目的 熟悉Linux开发环境并学会Linux开发环境的配置和使用&#xff0c;熟悉arm箱的使用&#xff0c;熟悉以下知识点&#…

上海居民被垃圾分类逼疯!这款垃圾自动分类器也许能帮上忙

作者 | 视说君来源 | 授权转载自视说AI&#xff08;ID:techtalkai&#xff09;让垃圾自动分类近期垃圾分类成为了一个热门话题&#xff0c;原来直接一次性扔掉的垃圾&#xff0c;现在都需要分门别类进行投放。从今年7月1日起&#xff0c;新的《上海市生活垃圾管理条例》正式开始…

虽被BERT碾压,但还是有必要谈谈BERT时代与后时代的NLP

作者 | 吴金龙&#xff0c;爱因互动技术合伙人&#xff0c;算法负责人来源 | 授权转载自AINLP&#xff08;ID:nlpjob&#xff09;2018年是NLP的收获大年&#xff0c;模型预训练技术终于被批量成功应用于多项NLP任务。之前搞NLP的人一直羡慕搞CV的人&#xff0c;在ImageNet上训练…

C++ 简单读写文本文件、统计文件的行数、读取文件数据到数组

转自&#xff1a;http://hi.baidu.com/ctralt/blog/item/cde79fec87f841302697911c.html fstream提供了三个类&#xff0c;用来实现c对文件的操作。&#xff08;文件的创建、读、写&#xff09;。ifstream -- 从已有的文件读 ofstream -- 向文件写内容 fstream - 打开文件供读写…

Exchange 2007迁移2010时的公用文件夹多个公用树错误

近期在项目中&#xff0c;客户Exchange 从2007迁移到2010&#xff0c;Microsoft Exchange从2007开始就逐渐弱化了公用文件夹&#xff0c;outlook 2007和2010都不需要使用到公用文件夹了。但客户现状存在90%的outlook 2003客户端&#xff0c;因此需要使用到公用文件夹。在Exchan…

约瑟夫环问题的两种解法(详解)

约瑟夫环问题的两种解法&#xff08;详解&#xff09; 题目&#xff1a; Josephus有过的故事&#xff1a;39 个犹太人与Josephus及他的朋友躲到一个洞中&#xff0c;39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式&#xff0c;41个人排成一个圆圈&#xff0c;由第1个…

Linux下多播的配置【十全十美】

单播地址标识单个IP接口&#xff0c;广播地址标识某个子网的所有IP接口。多播地址表示某一组IP接口&#xff0c;单播和广播是寻址方案中的两个极端(要么单个要么全部)&#xff0c;多播则意在两者之间提供一种折中方案。多播是用于建立分布式系统的重要工具&#xff0c;例如&…

CvSeq相关函数

转自&#xff1a;http://hi.baidu.com/pengjun/blog/item/a72fc8ea030e79d4d439c906.html 函数原型说明CvSeq* cvCreateSeq(int seq_flags,int header_size,int elem_size,CvMemStorage* storage)功能&#xff1a;创建一序列 参数&#xff1a;seq_flags为序列的符号标志。如果序…

10月份机房技术指标

下载syslinux&#xff0c;dhcp&#xff0c;http&#xff0c;tftp-serveryum -y install syslinux dhcp httpd tftp-serveryum -y install system-config-kickstart挂载sr0是镜像用system-config-kickstart工具来生成一个自动的安装的配置文件ip填自己的ip地址。目录填挂载光盘的…

5G时代,微软又走对了一步棋!

2019年4月&#xff0c;CSDN采访微软&#xff08;中国&#xff09;首席技术官韦青&#xff0c;期间谈到5G。他认为&#xff0c;5G绝对是一个划时代的革命性突破&#xff0c;但是这个突破不止于现在所说的“5G”通讯技术&#xff0c;它为未来以“万物互联”为基础的智能社会开创了…

6426C Lab3 部署证书和管理注册

共有4个练习&#xff1a;练习1&#xff1a;配置证书模板练习2&#xff1a;配置自动注册练习3&#xff1a;管理证书 Revocation练习4&#xff1a;配置Key Recovery练习1&#xff1a;任务1&#xff1a;复制、安装和手动注册一个证书1. 转到HQDC1.contoso.com服务器&#xff0c;添…

CreateStructuringElementEx

转自&#xff1a;http://baike.baidu.com/view/4819443.htm CreateStructuringElementEx 创建结构元素 IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y, int shape, int* valuesNULL ); cols 结构元素的列数目 rows 结构…

阿里AI再摘一冠,大幅提高视觉对话世界纪录

近日&#xff0c; 在第二届视觉对话挑战赛Visual Dialogue Challenge中&#xff0c;阿里AI击败了微软、首尔大学等十支参赛队伍&#xff0c;获得冠军。 &#xff08;阿里AI在视觉对话竞赛中得冠&#xff09;视觉对话竞赛由美国佐治亚理工大学、Facebook人工智能实验室&#xff…

OSChina 周一乱弹 —— 嫂子我帮你们照顾放心吧

2019独角兽企业重金招聘Python工程师标准>>> Osc乱弹歌单&#xff08;2018&#xff09;请戳&#xff08;这里&#xff09; 【今日歌曲】 clouddyy &#xff1a;#每日一歌# 《绿光 - 孙燕姿》 《绿光》 - 孙燕姿 手机党少年们想听歌&#xff0c;请使劲儿戳&#xff0…

十一月工作小记--上线前的冲刺

加班不是目的&#xff0c;重要的是找到加班的意义。尽管程序猿们有很多个不愿意&#xff0c;他们却依然要面对加班的现实。加班就是程序猿们生活中的一张牌&#xff0c;既然不能决定这张牌是什么&#xff0c;那就想想如何去打好这张牌吧。本月&#xff0c;我们的生活依然是那么…

Java跌落神坛,Python继续夺冠....凭啥?

编程语言流行指数(PYPL)排行榜近日公布了2019年6月份榜单。相比 5 月编程语言榜单&#xff0c;Python 不仅超过了 C&#xff0c;成功占据第三名位置&#xff0c;还以 2.77% 的涨幅成为增速最快的编程语言&#xff0c;与此同时&#xff0c;拥有 8.53% 份额的 Python 达到了 TIOB…

opencv实现二值图像细化的算法

转自&#xff1a;http://blog.csdn.net/byxdaz/archive/2010/06/02/5642669.aspx 细化算法通常和骨骼化、骨架化算法是相同的意思&#xff0c;也就是thin算法或者skeleton算法。虽然很多图像处理的教材上不是这么写的&#xff0c;具体原因可以看这篇论文&#xff0c;Louisa Lam…

@芥末的糖----------《管理系统后台架构逻辑》

mongo逻辑 //1.创建mongoose对象链接数据库&#xff0c;并暴露 var mongoose require(mongoose) mongoose.connect(mongodb://localhost:27017/lagou, {useNewUrlParser: true })var db mongoose.connection db.on(error, console.error.bind(console, connection error:)) d…

PHP函数之无极分类

无极分类属于现在比较难攻克的一关&#xff0c;现在就把代码贴出来&#xff0c;有需要的朋友可以根据实际需要扩展一下。 //假设分类关系为“ 地球”&#xff08;id为1&#xff0c;父id为0&#xff09;&#xff0c;“国家”&#xff08;id为2&#xff0c;父id为1&#xff09;&a…

我发现了一个非常酷的软件,用自然语言编程!

作者 | 刘欣&#xff0c;前IBM架构师&#xff0c;用15年的技术工作经验去总结提炼&#xff0c;以故事讲解技术本质&#xff0c;让大家看过以后有一种“原来如此”的感觉。来源 | 码农翻身&#xff08;公众号id&#xff1a;coderising&#xff09;周六晚上10点半&#xff0c; 张…

Matlab中去除exe执行时文件的DOS窗口的方法

转自&#xff1a;http://www.matlabsky.com/thread-547-1-1.html 方法1在command window中输入如下命令&#xff1a; cd(prefdir) edit compopts.bat 此时compopts.bat打开&#xff0c;在文件最后添加 A.VC环境下&#xff1a; set LINKFLAGS%LINKFLAGS%/SUBSYSTEM:WINDOWS /ENT…

ubuntu14.04 升级gcc的方法

Ubuntu12..4版本也可正常安装。 1、添加软件源 sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update2、安装gcc高版本&#xff0c;gcc4.8&#xff0c;gcc4.9&#xff0c;gcc5 gcc4.8 sudo apt-get upgrade sudo apt-get install gcc-4.8 g-4.8gcc4.9 sud…

Java 基础【04】Swing 组件事件注册

聪明出于勤奋&#xff0c;天才在于积累。——华罗庚 对上次的三个问题的个人理解&#xff1a; 1&#xff09; 程序首先是从main函数开始执行的&#xff0c;假设main 函数不是 static &#xff0c;就要先实例化这个类&#xff0c;然后调用 main 方法&#xff0c;这似乎是不现实…

VC++ 隐藏控制台程序窗口

转自&#xff1a;http://hi.baidu.com/sicceer/blog/item/d9c35a810d15c4c8bc3e1ec8.html 设置 #pragma comment( linker, "/subsystem:/ "windows/ " /entry:/ "mainCRTStartup/ " " ) // 设置入口地址 这样就ok了 在控制台程序中隐藏控制台窗口…

深度学习原来还可以这么学!

最近身边很多朋友在讨论人工智能&#xff0c;讨论人工智能在我们生活中的应用&#xff0c;随之而来就开始讨论深度学习技术&#xff0c;但是由于深度学习的涉及面比较广&#xff0c;对数学的要求比较高&#xff0c;所以想学也不太敢学&#xff0c;生怕认真学了却没学会。其实可…

016-热更新之FishingJoy一

我们在完成对xlua的学习后&#xff0c;现在我们在接下来的几天中&#xff0c;将会用一个案例来学习一下xlua的使用。请大家不用担心&#xff0c;这个课件的使用是基于xlua而开发的。因为我们在这个部分是为了使用xlua&#xff0c;所以我们只在已经做到的案例上进行xlua的学习。…

从0到1 | 手把手教你如何使用哈工大NLP工具——PyLTP!

作者 | 杨秀璋来源 | CSDN 博客&#xff08;CSDN id&#xff1a;Eastmount&#xff09;&#xff08;本文经作者授权&#xff0c;此系列文章整理后微信平台首发于AI科技大本营&#xff09;【导语】此文是作者基于 Python 构建知识图谱的系列实践教程&#xff0c;具有一定创新性和…

PL/SQL Developer远程访问Oracle数据库

安装oracle对应的版本 &#xff0c;在oracle的安装目录找到oracle\product\11.2.0\dbhome_1\NETWORK\ADMIN\tnsnames.ora这个文件添加上数据库访问的串 LWZC (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST [服务器地址])(PORT 1521))(CONNECT_DATA (SERVER DEDICATED)(SE…

基于shiro的权限设计

shiro介绍 Apache shiro是一个权限控制框架&#xff0c;它将安全认证抽取出来&#xff0c;实现用户身份认证&#xff0c;权限授权&#xff0c;加密&#xff0c;会话管理等功能&#xff0c;是一个通用的安全认证框架&#xff0c;而且还可以用于分布式集群。功能如下 1.验证用户 …