• Linux网络编程之connect函数分析


    在一个 CLIENT/SERVER模型的网络应用中,客户端的调用序列大致如下:

            socket -> connect -> recv/send -> close

            其中socket没有什么可疑问的,主要是创建一个套接字用于与服务端交换数据,并且通常它会迅速返回,此时并没有数据通过网卡发送出去,而紧随其后的connect函数则会产生网络数据的发送,TCP的三次握手也正是在此时开始,connect会先发送一个SYN包给服务端,并从最初始的CLOSED状态进入到SYN_SENT状态,在此状态等待服务端的确认包,通常情况下这个确认包会很快到达,以致于我们根本无法使用netstat命令看到SYN_SENT状态的存在,不过我们可以做一个极端情况的模拟,让客户端去连接一个随意指定服务器(如IP地址为88.88.88.88),因为该服务器很明显不会反馈给我们SYN包的确认包(SYN ACK),客户端就会在一定时间内处于SYN_SENT状态,并在预定的超时时间(比如3分钟)之后从connect函数返回,connect调用一旦失败(没能到达ESTABLISHED状态)这个套接字便不可用,若要再次调用connect函数则必须要重新使用socket函数创建新的套接字。


    下面结合实例分析,客户端代码如下:

    1. /** 
    2.  * client.c 
    3.  * 
    4.  * TCP client program, it is a simple example only. 
    5.  * Writen By: Zhou Jianchun 
    6.  * Date: 2011.08.11 
    7.  * 
    8.  * Compiled With: gcc -o client client.c 
    9.  * Tested On: Ubuntu 11.04 LTS 
    10.  * gcc version: 4.5.2 
    11.  * 
    12.  */  
    13.   
    14. #include <stdio.h>  
    15. #include <sys/socket.h>  
    16. #include <unistd.h>  
    17. #include <sys/types.h>  
    18. #include <netinet/in.h>  
    19. #include <stdlib.h>  
    20. #include <string.h>  
    21. #include <errno.h>  
    22.   
    23. #define SERVER_PORT 20000  
    24.   
    25. void usage(char *name)  
    26. {  
    27.     printf("usage: %s IP\n", name);  
    28. }  
    29. int main(int argc, char **argv)  
    30. {  
    31.     int server_fd, client_fd, length = 0;  
    32.     struct sockaddr_in server_addr, client_addr;  
    33.     socklen_t socklen = sizeof(server_addr);  
    34.   
    35.     if(argc < 2)  
    36.     {  
    37.         usage(argv[0]);  
    38.         exit(1);  
    39.     }  
    40.     if((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
    41.     {  
    42.         printf("create socket error, exit!\n");  
    43.         exit(1);  
    44.     }  
    45.     srand(time(NULL));  
    46.     bzero(&client_addr, sizeof(client_addr));  
    47.     client_addr.sin_family = AF_INET;  
    48.     client_addr.sin_addr.s_addr = htons(INADDR_ANY);  
    49.   
    50.     bzero(&server_addr, sizeof(server_addr));  
    51.     server_addr.sin_family = AF_INET;  
    52.     inet_aton(argv[1], &server_addr.sin_addr);  
    53.     server_addr.sin_port = htons(SERVER_PORT);  
    54.   
    55.     if(connect(client_fd, (struct sockaddr*)&server_addr, socklen) < 0)  
    56.     {  
    57.         printf("can not connect to %s, exit!\n", argv[1]);  
    58.         printf("%s\n", strerror(errno));  
    59.         exit(1);  
    60.     }  
    61.     return 0;  
    62. }  

    编译完成之后执行:

    1. zhou@neptune:~/data/source$ ./client 88.88.88.88  

    此时程序会在connect函数中阻塞等待,约180秒之后输出:

    1. can not connect to 88.88.88.88, exit!  
    2. Connection timed out  

    此刻connect的返回值为ETIMEOUT。

    在此过程中我们可以用netstat命令查询连接状态:

    1. zhou@neptune:~/data/source$ sudo netstat -natp |grep 20000  
    2. tcp        0      1 192.168.0.4:44203       88.88.88.88:20000       SYN_SENT    5954/client      

    可以看到此时的TCP连接状态为SYN_SENT,也就意味着发送了SYN包之后一直未得到服务端回馈SYN ACK包。

    接下来我们使用这个客户端程序来连接自己的机器,测试时我的IP地址是192.168.0.4,是一个无线局域网,结果如下:

    1. zhou@neptune:~/data/source$ ./client 192.168.0.4  
    2. can not connect to 192.168.0.4, exit!  
    3. Connection refused  

    因为我的机器上并没有跑在指定端口(20000)上监听的服务端程序,所以这个连接直接被协议栈拒绝(通过发送RST类型的TCP包),connect立刻返回,返回值为ECONNREFUSED。

    再来看看去连接同一局域网中一台不存在的主机时的情形,比如这台想象的主机的IP地址为192.168.0.188:

    1. zhou@neptune:~/data/source$ ./client 192.168.0.188  
    2. can not connect to 192.168.0.188, exit!  
    3. No route to host  

    因为本地局域网中的该主机并不存在,ARP请求得不到回应,网关会回应主机不可达的ICMP报文,connect返回EHOSTUNREACH。

    至此connect函数的分析就结束了,由于本人水平有限,博客中的不妥或错误之处在所难免,殷切希望读者批评指正。同时也欢迎读者共同探讨相关的内容,如果乐意交流的话请留下您宝贵的意见,谢谢。


    原博文地址:http://blog.csdn.net/polarbearboy/article/details/6678838


  • 相关阅读:
    centos7 hbase 搭建笔记
    【转】python 2.6.6升级到python 2.7.x版本的方法
    centos7 sqoop 1 搭建笔记
    centos7 hive + 远程mysql 搭建笔记
    docker 批量操作容器
    centos7 hdfs yarn spark 搭建笔记
    【转】mysql查看表空间占用情况
    【转】Centos 7 修改主机名hostname
    jQuery选择
    jQuery检查复选框是否被选
  • 原文地址:https://www.cnblogs.com/java20130726/p/3218515.html
Copyright © 2020-2023  润新知