~/cpp$ ./connect 192.168.1.234 1234 kkkk

block mode:  ubuntu 14.04 : time used:21.0.001053s

connect 超时时间是大约21秒!

注意:如果connect 127.x.x.x  xxx  kkkk 会立即返回因为127开头的是网卡自身,你可以ping一下,发现都是通的,且等同于127.0.0.1

  1. #include <sys/socket.h>
  2. #include <arpa/inet.h>
  3. #include <assert.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <stdlib.h>
  9. #include <fcntl.h>
  10. #include <sys/time.h>
  11.  
  12. #define BUFFER_SIZE 512
  13.  
  14. int setnonblocking( int fd )
  15. {
  16. int old_option = fcntl( fd, F_GETFL );
  17. int new_option = old_option | O_NONBLOCK;
  18. fcntl( fd, F_SETFL, new_option );
  19. return old_option;
  20. }
  21.  
  22. int main( int argc, char* argv[] )
  23. {
  24. if( argc <= 3 )
  25. {
  26. printf( "usage: %s ip_address port_number send_bufer_size\n", basename( argv[0] ) );
  27. return 1;
  28. }
  29. const char* ip = argv[1];
  30. int port = atoi( argv[2] );
  31.  
  32. struct sockaddr_in server_address;
  33. bzero( &server_address, sizeof( server_address ) );
  34. server_address.sin_family = AF_INET;
  35. inet_pton( AF_INET, ip, &server_address.sin_addr );
  36. server_address.sin_port = htons( port );
  37.  
  38. int sock = socket( PF_INET, SOCK_STREAM, 0 );
  39. assert( sock >= 0 );
  40.  
  41. int sendbuf = atoi( argv[3] );
  42. int len = sizeof( sendbuf );
  43. setsockopt( sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, sizeof( sendbuf ) );
  44. getsockopt( sock, SOL_SOCKET, SO_SNDBUF, &sendbuf, ( socklen_t* )&len );
  45. printf( "the tcp send buffer size after setting is %d\n", sendbuf );
  46.  
  47. int old_option = fcntl( sock, F_GETFL );
  48. printf("noblock: %d\n", old_option & O_NONBLOCK); //0-->block mode
  49.  
  50. //int oldopt = setnonblocking(sock); set nonblock mode!
  51.  
  52. struct timeval tv1, tv2;
  53. gettimeofday(&tv1, NULL);
  54.  
  55. int ret = connect( sock, ( struct sockaddr* )&server_address, sizeof( server_address ) );
  56. printf("connect ret code is: %d\n", ret);
  57. if ( ret == 0 )
  58. {
  59. //
  60. printf("call getsockname ...\n");
  61. struct sockaddr_in local_address;
  62. socklen_t length;
  63. int ret = getpeername(sock, ( struct sockaddr* )&local_address, &length);
  64. assert(ret == 0);
  65. char local[INET_ADDRSTRLEN ];
  66. printf( "local with ip: %s and port: %d\n",
  67. inet_ntop( AF_INET, &local_address.sin_addr, local, INET_ADDRSTRLEN ), ntohs( local_address.sin_port ) );
  68. //
  69.  
  70. char buffer[ BUFFER_SIZE ];
  71. memset( buffer, 'a', BUFFER_SIZE );
  72. send( sock, buffer, BUFFER_SIZE, 0 );
  73. }
  74. else if (ret == -1)
  75. {
  76. gettimeofday(&tv2, NULL);
  77. suseconds_t msec = tv2.tv_usec - tv1.tv_usec;
  78. time_t sec = tv2.tv_sec - tv1.tv_sec;
  79. printf("time used:%d.%fs\n", sec, (double)msec / 1000000 );
  80.  
  81. printf("connect failed...\n");
  82. if (errno == EINPROGRESS)
  83. {
  84. printf("unblock mode ret code...\n");
  85. }
  86. }
  87. else
  88. {
  89. printf("ret code is: %d\n", ret);
  90. }
  91.  
  92. printf("after connected!\n");
  93.  
  94. close( sock );
  95. return 0;
  96. }

  

非阻塞模式:

  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <arpa/inet.h>
  5. #include <stdlib.h>
  6. #include <assert.h>
  7. #include <stdio.h>
  8. #include <time.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <sys/ioctl.h>
  12. #include <unistd.h>
  13. #include <string.h>
  14.  
  15. #define BUFFER_SIZE 1023
  16.  
  17. int setnonblocking( int fd )
  18. {
  19. int old_option = fcntl( fd, F_GETFL );
  20. int new_option = old_option | O_NONBLOCK;
  21. fcntl( fd, F_SETFL, new_option );
  22. return old_option;
  23. }
  24.  
  25. int unblock_connect( const char* ip, int port, int time )
  26. {
  27. int ret = 0;
  28. struct sockaddr_in address;
  29. bzero( &address, sizeof( address ) );
  30. address.sin_family = AF_INET;
  31. inet_pton( AF_INET, ip, &address.sin_addr );
  32. address.sin_port = htons( port );
  33.  
  34. int sockfd = socket( PF_INET, SOCK_STREAM, 0 );
  35. int fdopt = setnonblocking( sockfd );
  36. ret = connect( sockfd, ( struct sockaddr* )&address, sizeof( address ) );
  37. printf("connect ret code = %d\n", ret);
  38. if ( ret == 0 )
  39. {
  40. printf( "connect with server immediately\n" );
  41. fcntl( sockfd, F_SETFL, fdopt ); //set old optional back
  42. return sockfd;
  43. }
  44. //unblock mode --> connect return immediately! ret = -1 & errno=EINPROGRESS
  45. else if ( errno != EINPROGRESS )
  46. {
  47. printf("ret = %d\n", ret);
  48. printf( "unblock connect failed!\n" );
  49. return -1;
  50. }
  51. else if (errno == EINPROGRESS)
  52. {
  53. printf( "unblock mode socket is connecting...\n" );
  54. }
  55.  
  56. //use select to check write event, if the socket is writable, then
  57. //connect is complete successfully!
  58. fd_set readfds;
  59. fd_set writefds;
  60. struct timeval timeout;
  61.  
  62. FD_ZERO( &readfds );
  63. FD_SET( sockfd, &writefds );
  64.  
  65. timeout.tv_sec = time; //timeout is 10 minutes
  66. timeout.tv_usec = 0;
  67.  
  68. ret = select( sockfd + 1, NULL, &writefds, NULL, &timeout );
  69. if ( ret <= 0 )
  70. {
  71. printf( "connection time out\n" );
  72. close( sockfd );
  73. return -1;
  74. }
  75.  
  76. if ( ! FD_ISSET( sockfd, &writefds ) )
  77. {
  78. printf( "no events on sockfd found\n" );
  79. close( sockfd );
  80. return -1;
  81. }
  82.  
  83. int error = 0;
  84. socklen_t length = sizeof( error );
  85. if( getsockopt( sockfd, SOL_SOCKET, SO_ERROR, &error, &length ) < 0 )
  86. {
  87. printf( "get socket option failed\n" );
  88. close( sockfd );
  89. return -1;
  90. }
  91.  
  92. if( error != 0 )
  93. {
  94. printf( "connection failed after select with the error: %d \n", error );
  95. close( sockfd );
  96. return -1;
  97. }
  98.  
  99. //connection successful!
  100. printf( "connection ready after select with the socket: %d \n", sockfd );
  101. fcntl( sockfd, F_SETFL, fdopt ); //set old optional back
  102. return sockfd;
  103. }
  104.  
  105. int main( int argc, char* argv[] )
  106. {
  107. if( argc <= 2 )
  108. {
  109. printf( "usage: %s ip_address port_number\n", basename( argv[0] ) );
  110. return 1;
  111. }
  112. const char* ip = argv[1];
  113. int port = atoi( argv[2] );
  114.  
  115. int sockfd = unblock_connect( ip, port, 10 );
  116. if ( sockfd < 0 )
  117. {
  118. printf("sockfd error! return -1\n");
  119. return 1;
  120. }
  121. //shutdown( sockfd, SHUT_WR ); //disable read and write
  122. printf( "send data out\n" );
  123. send( sockfd, "abc", 3, 0 );
  124. shutdown( sockfd, SHUT_WR ); //disable read and write
  125. close(sockfd);
  126. return 0;
  127. }

  

建立socket后默认connect()函数为阻塞连接状态,在大多数实现中,connect的超时时间在75s至几分钟之间,想要缩短超时时间,可解决问题的两种方法:方法一、将socket句柄设置为非阻塞状态,方法二、采用信号处理函数设置阻塞超时控制。

在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未完成;同时TCP的三路握手操作继续进行;在这之后,我们可以调用select来检查这个链接是否建立成功;非阻塞connect有三种用途:
1.我们可以在三路握手的同时做一些其它的处理.connect操作要花一个往返时间完成,而且可以是在任何地方,从几个毫秒的局域网到几百毫秒或几秒的广域网.在这段时间内我们可能有一些其他的处理想要执行;
2.可以用这种技术同时建立多个连接.在Web浏览器中很普遍;
3.由于我们使用select来等待连接的完成,因此我们可以给select设置一个时间限制,从而缩短connect的超时时间.在大多数实现中,connect的超时时间在75秒到几分钟之间.有时候应用程序想要一个更短的超时时间,使用非阻塞connect就是一种方法;
非阻塞connect听起来虽然简单,但是仍然有一些细节问题要处理:
1.即使套接口是非阻塞的,如果连接的服务器在同一台主机上,那么在调用connect建立连接时,连接通常会立即建立成功.我们必须处理这种情况;
2.源自Berkeley的实现(和Posix.1g)有两条与select和非阻塞IO相关的规则:
A:当连接建立成功时,套接口描述符变成可写;
B:当连接出错时,套接口描述符变成既可读又可写;
注意:当一个套接口出错时,它会被select调用标记为既可读又可写;

非阻塞connect有这么多好处,但是处理非阻塞connect时会遇到很多可移植性问题;

处理非阻塞connect的步骤:
第一步:创建socket,返回套接口描述符;
第二步:调用fcntl把套接口描述符设置成非阻塞;
第三步:调用connect开始建立连接;
第四步:判断连接是否成功建立;
A:如果connect返回0,表示连接简称成功(服务器可客户端在同一台机器上时就有可能发生这种情况);
B:调用select来等待连接建立成功完成;
如果select返回0,则表示建立连接超时;我们返回超时错误给用户,同时关闭连接,以防止三路握手操作继续进行下去;
如果select返回大于0的值,则需要检查套接口描述符是否可读或可写;如果套接口描述符可读或可写,则我们可以通过调用getsockopt来得到套接口上待处理的错误(SO_ERROR),如果连接建立成功,这个错误值将是0,如果建立连接时遇到错误,则这个值是连接错误所对应的errno值(比如:ECONNREFUSED,ETIMEDOUT等).
"读取套接口上的错误"是遇到的第一个可移植性问题;如果出现问题,getsockopt源自Berkeley的实现是返回0,等待处理的错误在变量errno中返回;但是Solaris会让getsockopt返回-1,errno置为待处理的错误;我们对这两种情况都要处理;

这样,在处理非阻塞connect时,在不同的套接口实现的平台中存在的移植性问题,首先,有可能在调用select之前,连接就已经建立成功,而且对方的数据已经到来.在这种情况下,连接成功时套接口将既可读又可写.这和连接失败时是一样的.这个时候我们还得通过getsockopt来读取错误值;这是第二个可移植性问题;
移植性问题总结:
1.对于出错的套接口描述符,getsockopt的返回值源自Berkeley的实现是返回0,待处理的错误值存储在errno中;而源自Solaris的实现是返回-1,待处理的错误存储在errno中;(套接口描述符出错时调用getsockopt的返回值不可移植)
2.有可能在调用select之前,连接就已经建立成功,而且对方的数据已经到来,在这种情况下,套接口描述符是既可读又可写;这与套接口描述符出错时是一样的;(怎样判断连接是否建立成功的条件不可移植)

这样的话,在我们判断连接是否建立成功的条件不唯一时,我们可以有以下的方法来解决这个问题:
1.调用getpeername代替getsockopt.如果调用getpeername失败,getpeername返回ENOTCONN,表示连接建立失败,我们必须以SO_ERROR调用getsockopt得到套接口描述符上的待处理错误;
2.调用read,读取长度为0字节的数据.如果read调用失败,则表示连接建立失败,而且read返回的errno指明了连接失败的原因.如果连接建立成功,read应该返回0;
3.再调用一次connect.它应该失败,如果错误errno是EISCONN,就表示套接口已经建立,而且第一次连接是成功的;否则,连接就是失败的;

被中断的connect:
如果在一个阻塞式套接口上调用connect,在TCP的三路握手操作完成之前被中断了,比如说,被捕获的信号中断,将会发生什么呢?假定connect不会自动重启,它将返回EINTR.那么,这个时候,我们就不能再调用connect等待连接建立完成了,如果再次调用connect来等待连接建立完成的话,connect将会返回错误值EADDRINUSE.在这种情况下,应该做的是调用select,就像在非阻塞式connect中所做的一样.然后,select在连接建立成功(使套接口描述符可写)或连接建立失败(使套接口描述符既可读又可写)时返回;

方法二、定义信号处理函数:

  1. sigset(SIGALRM, u_alarm_handler);
  2. alarm(2);
  3. code = connect(socket_fd, (struct sockaddr*)&socket_st, sizeof(struct sockaddr_in));
  4. alarm(0);
  5. sigrelse(SIGALRM);

首先定义一个中断信号处理函数u_alarm_handler,用于超时后的报警处理,然后定义一个2秒的定时器,执行connect,当系统connect成功,则系统正常执行下去;如果connect不成功阻塞在这里,则超过定义的2秒后,系统会产生一个信号,触发执行u_alarm_handler函数, 当执行完u_alarm_handler后,程序将继续从connect的下面一行执行下去。
其中,处理函数可以如下定义,也可以加入更多的错误处理。

    1. void u_alarm_handler()
    2. {
    3. }

linux-socket connect阻塞和非阻塞模式 示例的更多相关文章

  1. 面向连接的socket数据处理过程以及非阻塞connect问题

    对于面向连接的socket类型(SOCK_STREAM,SOCK_SEQPACKET)在读写数据之前必须建立连接,首先服务器端socket必须在一个客户端知道的地址进行监听,也就是创建socket之后 ...

  2. 从linux源码看socket的阻塞和非阻塞

    从linux源码看socket的阻塞和非阻塞 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 大部分高性能网络框架采用的是非阻塞模式.笔者这次就从linux ...

  3. UDP socket 设置为的非阻塞模式

    UDP socket 设置为的非阻塞模式 Len = recvfrom(SocketFD, szRecvBuf, sizeof(szRecvBuf), MSG_DONTWAIT, (struct so ...

  4. linux socket设置阻塞与非阻塞

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:       基本概念: 阻塞IO:: socket 的阻塞模式 ...

  5. socket阻塞与非阻塞,同步与异步、I/O模型,select与poll、epoll比较

    1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就 ...

  6. socket阻塞与非阻塞,同步与异步

    socket阻塞与非阻塞,同步与异步 作者:huangguisu 转自:http://blog.csdn.net/hguisu/article/details/7453390 1. 概念理解 在进行网 ...

  7. socket编程的同步、异步与阻塞、非阻塞示例详解

     socket编程的同步.异步与阻塞.非阻塞示例详解之一  分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...

  8. socket阻塞与非阻塞,同步与异步、I/O模型

    socket阻塞与非阻塞,同步与异步 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:同步:      所 ...

  9. socket阻塞与非阻塞,同步与异步I/O模型

    作者:huangguisu 原文出处:http://blog.csdn.NET/hguisu/article/details/7453390 socket阻塞与非阻塞,同步与异步 1. 概念理解 在进 ...

  10. socket阻塞与非阻塞,同步与异步,select,pool,epool

    概念理解 一.与I/O相关的五个重要概念 1. 第一个概念:用户空间与内核空间 1. 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方) 2. ...

随机推荐

  1. 1601O_HOME

    马kaiyu   https://blog.csdn.net/debugbugbg 胡guoxin https://blog.csdn.net/qq_41995727 张yizhong  https: ...

  2. RESTful 个人理解总结【转】

    转自:http://www.cnblogs.com/wang-yaz/p/9237981.html 一.什么是RESTful 面向资源 简单的说:RESTful是一种架构的规范与约束.原则,符合这种规 ...

  3. 使用Python编写简单的端口扫描器的实例分享【转】

    转自 使用Python编写简单的端口扫描器的实例分享_python_脚本之家 http://www.jb51.net/article/76630.htm -*- coding:utf8 -*- #!/ ...

  4. WebBrowserのIEバージョンを最新にする。

    WindowsフォームでWebBrowserコントロールを配置すると.IEのバージョンが 7 と古い.レジストリをいじると.IE11の Edgeモードに変更できる(参考記事).デザイン画面でWebBr ...

  5. java Foreach与迭代器

    foreach语法主要用于数组,但是它也可以用于Collection对象,下面是一个示例 package object; //: holding/ForEachCollections.java // ...

  6. github git 无法读取远程仓库或无权限

    解决方法:重新设置ssh密钥 ssh-keygen -t rsa -C "http://github.com"//输入命令后按提示输入id_rsa.pub的存储地址 和密钥密码 地 ...

  7. .NetCore中结合ExceptionLess的处理对Polly再次封装

    /// <summary> /// Polly封装 liyouming /// </summary> public class PollyServicesFactory { p ...

  8. 如何写django中form的测试用例

    可简可繁, 可插库,可字符, 要测试valid,也要测试invalid, 可用csrf,也可用context. 放一个全面的, 实践中,找一个最优的组合就好. class NewTopicTests( ...

  9. 使用prometheus抓取k8s的metrics作监控时,cAdvisor和kubelet配置有何差别?

    按网上说法: 目前cAdvisor集成到了kubelet组件内,可以在kubernetes集群中每个启动了kubelet的节点使用cAdvisor提供的metrics接口获取该节点所有容器相关的性能指 ...

  10. k8s的imagePullSecrets如何生成及使用

    如果公司的docker仓库(harbor),需要用户认证之后,才能拉取镜像. 那如何在k8s里生成这个secret呢? 这个secret如何还原呢? 在k8s的yaml文件里如何实现呢? 这里提供几个 ...