• 利用tcpdump分析工具来验证tcp连接的建立和关闭过程


      本文要求读者在阅读之前应该对TCP通过三次握手建立和关闭连接有一定的了解,本文并没有详细讲解三次握手,只是通过一个实例对三次握手进行了一下验证。

      tcp连接的建立和关闭想必大家都已经非常熟悉了!通过三次握手建立连接和通过三次或者四次(半关闭)握手来关闭连接!在这里,我想通过一个具体的实例程序,来分析一下这个过程!

      首先说用到的工具吧,linux下的tcpdump命令,和自己用c语言写的一个服务器端和一个客户端程序。程序的代码如下:

      头文件:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<sys/socket.h>
     5 #include<netinet/in.h>
     6 #include<netdb.h>
     7 #include<errno.h>
     8 #include<signal.h>
     9 #include<unistd.h>
    10 #include<string.h>
    11 #include<sys/wait.h>
    12 #include<arpa/inet.h>
    Header

      服务器端:

     1 #include"header.h"
     2 int main(int argc,char *argv[])
     3 {
     4     int socket_n;    //套接字描述符
     5     int listen_s;    //监听套接字描述符
     6     socklen_t cli_addr_len;            //客户端地址长度
     7     struct sockaddr_in server_addr; //服务器地址
     8     struct sockaddr_in client_addr; //客户端地址
     9 
    10     int n=0;        //接受到的数据长度
    11     char buffer[256];    //数据缓冲区
    12     int maxLen=sizeof(buffer);
    13     memset(buffer,0,maxLen);
    14     char cli_addr[20];
    15 
    16     //回创建监听套接字
    17     listen_s=socket(AF_INET,SOCK_STREAM,0);
    18 
    19     //创建本地服务器套接字
    20     memset(&server_addr,0,sizeof(server_addr));
    21     server_addr.sin_family = AF_INET;
    22     server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    23     server_addr.sin_port=htons(9877);
    24 
    25     //将套接字绑定到本地套接字地址
    26     if(bind(listen_s,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
    27     {
    28         perror("Error:binding failed!");
    29         exit(0);
    30     }
    31     //监听链接请求
    32     if(listen(listen_s,maxLen) < 0)
    33     {
    34     perror("Error:listening failed!");
    35     exit(1);
    36     }
    37 
    38     while(1)
    39     {
    40     if((socket_n=accept(listen_s,(struct sockaddr *)&client_addr,&cli_addr_len)) < 0)
    41     {
    42         perror("Error:accepting failed!");
    43         exit(1);
    44     }
    45     read(socket_n,buffer,maxLen);
    46     inet_ntop(AF_INET,&client_addr.sin_addr,cli_addr,sizeof(cli_addr));
    47     printf("%s sent %s",cli_addr,buffer);
    48     write(socket_n,buffer,strlen(buffer));
    49     printf("刚刚建立的连接即将关闭
    ");
    50     close(socket_n);
    51     }
    52     return 0;
    53 }
    Server

      客户端:

     1 #include"header.h"
     2 int main(int argc,char *argv[])
     3 {
     4     int sockfd;
     5     char buffer_s[256];
     6     char buffer_r[256];
     7     struct sockaddr_in servaddr;
     8 
     9     memset(buffer_r,0,sizeof(buffer_r));
    10     memset(buffer_s,0,sizeof(buffer_s));
    11 
    12     if(argc != 2)
    13     {
    14     printf("usage : client <IP address>!");
    15     exit(0);
    16     }
    17 
    18     sockfd = socket(AF_INET,SOCK_STREAM,0);
    19     
    20     memset(&servaddr,0,sizeof(servaddr));
    21     servaddr.sin_family = AF_INET;
    22     servaddr.sin_port = htons(9877);
    23     inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
    24 
    25     connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
    26 
    27     while(fgets(buffer_s,256,stdin) != NULL)
    28     {
    29     write(sockfd,buffer_s,strlen(buffer_s));
    30     if(read(sockfd,buffer_r,256) == 0)
    31     {
    32         printf("client:server terminated prematurely");   
    33     }
    34     fputs(buffer_r,stdout);
    35     }
    36 
    37     return 0;
    38 }
    Client

      tcpdump用的命令是这句:

    tcpdump -i lo tcp port 9877 and host 127.0.0.1

      这条命令表示,我抓取lo网卡(环回接口)上ip为127.0.0.1且端口号为9877(这个9877是我的程序中服务器绑定的接口)的包!

      运行的结果如下图:

       

      客户端发送一个"a "给服务器,并且接收到一个"a ";

      

      这个截的图有点多了,这个与本文有关的部分就是最底下的从./server 开始的部分,服务器接受到一个"a ",回传给客户端之后立刻将这个连接关闭,并且提示"刚刚建立的连接即将关闭"!

      

      这个是抓包软件抓到的图,这个就得好好分析分析了!

      首先需要说明几点的是,这个分析是从那个15:32:38.348872开始,那个38264表示的是客户端的端口号,9877表示的是服务器的端口号,关于有些包的符号位(图中flags部分)中应该有ACK这个标志,可是具体没有显示,我认为可能是tcpdump省略了,还有些包中的SYN符号(用一个S表示)也可能省略了。另外需要说明的一点是服务器和客户端的序号应该都是随机数,可是连接建立之后就自动从1开始,我认为这个是tcpdump这个软件自动进行了计算!

      第一条信息表示客户端发送给服务器一个包,其序号seq为598232472,标志位为SYN,就是建立连接的第一次握手。客户端发送自己的序号。

      第二条信息表示服务器发送给客户端一个包,其序号seq为3283581888,确认号为5982324272,标志位为SYC(理论上还应该有ACK,可能这里没有显示出来),这就是建立连接的第二次握手,服务器发送这边的序号,并对客户端的序号进行确认。

      第三条信息表示客户端发送给服务器一个包,没有序号,确认号为1(我认为这里是tcpdump这个抓包软件进行了处理),表示想要从服务器接受第一个字节,到这里,三次握手已经完成,客户端到服务器的连接已经建立。

      第四条信息表示客户端发送两个字节的信息给服务器,序号seq为1,确认号为1。标志位为PSH(表示不在窗口里面缓存,直接交给应用程序)。

      第五条信息表示服务器对客户端发送的信息表示确认,确认号为3,没有序号。

      第六条信息表示服务器发送给客户端两个字节的信息,序号为1,确认号为3.符号位为PSH。

      第七条信息表示服务器发送给客户端一个连接终止的FIN信息。序号为3,确认号为3,从这里开始了连接关闭的三次握手过程。(这里是服务器主动关闭的,所以三次握手就变成了二次握手~~)。

      第八条信息表示客户端发送给服务器的一个确认信息,确认号为3,表示对服务器发送的那两个字节的确认。

      第九条信息表示客户端发送一个确认信息给服务器,确认号为4,表示对服务器发送的FIN终止信息进行确认,至此,那个TCP连接也就关闭了。

      OK,这就是三次握手的实例,希望能够帮助大家更好地理解三次握手这个过程。

  • 相关阅读:
    C#Note13:如何在C#中调用python
    C# Note12:WPF只允许数字的限制性TextBox
    C# Note11:如何优雅地退出WPF应用程序
    C#读书笔记:线程,任务和同步
    Programming好文解读系列(—)——代码整洁之道
    java算法面试题:从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序 ;读取docx 读取doc 使用poi 相关jar包提集提供下载
    java面试题:如果一串字符如"aaaabbc中国1512"要分别统计英文字符的数量,中文字符的数量,和数字字符的数量,假设字符中没有中文字符、英文字符、数字字符之外的其他特殊字符。
    java算法面试题:有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出各个字符的个数 按值的降序排序,如果值相同则按键值的字母顺序
    java算法面试题:编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串,但要保证汉字不被截取半个, 如“我ABC”,4,应该截取“我AB”,输入“我ABC汉DEF”,6,应该输出“我ABC”,而不是“我ABC+汉的半个”。
    Java算法面试题:编写一个程序,将e: eck目录下的所有.java文件复制到e:jpg目录下,并将原来文件的扩展名从.java改为.jpg
  • 原文地址:https://www.cnblogs.com/bwangel23/p/4149529.html
Copyright © 2020-2023  润新知