• 07-网络篇-抓包分析TCP


    为了抓包方便一些,我在ubuntu虚拟机运行服务端程序,而在windows运行客户端程序,关于客户端与服务端程序如下。
    ##1.程序
    客户端:
    vs_client.cpp

    #include "stdafx.h"
    #include 
    #include 
    #pragma comment(lib,"ws2_32.lib")
    using namespace std;
    int main(){
    	WSADATA wsaData;
    	if(WSAStartup(MAKEWORD(2,2),&wsaData)){
    		cout<<"WinSock不能被初始化";
    		WSACleanup();
    		return 0;
    	}
    	SOCKET sockCli;
    	sockCli=socket(AF_INET,SOCK_STREAM,0);
    	SOCKADDR_IN addrSer;
    	addrSer.sin_family=AF_INET;
    	addrSer.sin_port=htons(8899);
    	addrSer.sin_addr.S_un.S_addr=inet_addr("192.168.6.139");
    	int res=connect(sockCli,(SOCKADDR *)&addrSer,sizeof(SOCKADDR));
    	if(res){
    		cout<<"客户端连接服务器失败"<<endl;
    		return -1;
    	}else{
    		cout<<"客户端连接服务器成功"<<endl;
    	}
    
    
    	//3.向服务端发送消息
    	char send_buf[256] = "hello server===>>>";
    	char recv_buf[512];
    	send(sockCli,send_buf,sizeof(send_buf),0);
    
    	//4.接收服务端发来的消息
    	int len = recv(sockCli,recv_buf,sizeof(recv_buf)-1,0);
    	recv_buf[len] = '\0';
    	printf("收到服务端的返回:%s\n",recv_buf);
    	Sleep(100);
    
    
    	closesocket(sockCli);
    	WSACleanup();
    	while(1)
    	{
    		Sleep(100);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    服务端
    sever.c

    #include 
    #include          
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
      //1.创建一个socket文件,也就是打开一个网络通讯端口
      int serv_sock = socket(AF_INET, SOCK_STREAM,0);
      
      //2.绑定服务器ip和端口到这个socket
      struct sockaddr_in serv_addr;
      memset(&serv_addr, 0, sizeof(serv_addr));//先清空一下初始的值,写上地址和端口号
      serv_addr.sin_family = AF_INET;
      serv_addr.sin_addr.s_addr = inet_addr("192.168.6.139");//本机ip
      serv_addr.sin_port = htons(8899);//随意选了一个端口8899
      bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
      
      //3.将socket设置为监听状态
      listen(serv_sock,128);//设置最大连接数为128
      
      //4.准备接收客户端的请求连接,这里的步骤可以重复进行,接收多个客户端的请求
      while(1){
        //接收客户端的请求连接后,返回一个新的socket(clnt_sock)用于和对应的客户端进行通信
        struct sockaddr_in clnt_addr;
        socklen_t clnt_addr_size = sizeof(clnt_addr);
        int clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size);
    
        //5.读取客户端发送来的数据
        char recv_buf[256];
        char send_buf[512]="hello client";
        int len = read(clnt_sock,recv_buf,sizeof(recv_buf)-1);
        recv_buf[len] = '\0';//字符串以“\0”结尾
        
        //6.打印出客户端发来的消息
        printf("recv client:%s\n",recv_buf);
        
        write(clnt_sock,send_buf,sizeof(send_buf));
    	sleep(3);
        
        //8.关闭客户端连接
        close(clnt_sock);
    	sleep(2);
        break;
    
      }
      //9.关闭服务端监听的socket
      close(serv_sock);
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在Ubuntu上,我们可以通过ifconfig命令,查看到系统的IP地址。

    $ ifconfig
    ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.6.139  netmask 255.255.255.0  broadcast 192.168.6.255
            inet6 fe80::8bc1:6df8:a7f2:95c5  prefixlen 64  scopeid 0x20<link>
            ether 00:0c:29:4a:43:e6  txqueuelen 1000  (Ethernet)
            RX packets 11886  bytes 3135825 (3.1 MB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 13969  bytes 11893886 (11.8 MB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ##2.抓包
    关于windows平台的抓包,这里不描述,本次测试抓的是服务端的包。
    首先在线安装抓包软件:我们用是是tcpdump,此软件可以在网上找到开源代码,假如用于嵌入式环境抓包,大家可以自己在网上下载源码后交叉编译
    sudo apt-get install tcpdump
    运行下面命令持续抓包,每一个包抓60秒。 可以自己调节-G后面参数设置每一个包的抓包时长:
    sudo tcpdump -i ens33 -s0 -G 60 -w %Y_%m%d_%H%M_%S.pcap

    得到抓包图如下
    抓包
    ##3.根据抓包分析Tcp
    这里通过分析Ack和Seq号,让大家了解Tcp为什么是可靠传输

    Seq(Sequence Number):
    32bits,表示这个tcp包的序列号。tcp协议拼凑接收到的数据包时,根据seq来确定顺序,并且能够确定是否有数据包丢失。

    Ack(Acknowledgment Number):
    32bits,表示这个包的确认号。首先意味着已经收到对方了多少字节数据,其次告诉对方接下来的包的seq要从ack确定的数值继续接力
    len:表示tcp携带的数据长度,不包括tcp头部信息的长度

    下面根据上面抓包来说明:关于包的序号,我在抓包图中已标明
    (1)三次握手
    (客户端)1号包:我能和你建立连接
    seq=0,表客户端第一条数据
    没有ack,因为前面没有收到数据,所以不用确认已收到
    Len=0。

    (服务端)2号包:我收到了请求
    seq=0,表此连接中,服务端第一条数据
    ack=1 表示收到了客户端的seq=0的连接请求,告诉客户端接下来请从seq=1开始传输数据
    Len=0,没有负载数据。

    (客户端)3号包:连接建立。
    seq=1,响应2号包
    ack=1,收到服务器seq=0同意连接,告诉服务端从seq=1传输数据
    Len=0

    (2)数据传输
    (客户端) 4号包:传256字节给服务端
    seq=1,上次没有传输数据,seq号不变,也就是3号包的seq=1,len=0
    ack=1,告诉服务端你要是发送数据,从seq=1开始
    len=256,表示我这次传输的数据字节数

    (服务端)5号包:响应。
    seq=1,4号包的ack所要求的
    ack=257,ack=(4号包的seq)+(4号包的len) = 1+256=257;下次客户端seq=257开始
    len=0

    (服务端)6号包:发512字节数据给客户端
    5、6号均为服务端发送的包,在这期间没有接收到包,所以,5、6号包的seq、ack是一样的。
    seq=1
    ack=257
    len=512,数据的长度

    (客户端)7号包:响应
    seq=257,5号包让从这个序列发
    ack=513,ack=(6号包的seq)+(6号包的len)=1+512=513
    len=0

    (3)总结一下
    3次握手的过程:
    (1).起始包的seq都等于0
    (2).三次握手中的ack=对方上一个的seq+1
    (3).seq等于对方上次的ack号

    数据发送过程:
    (1).发送方的包包括seq和len,接收方通过ack=发送方的seq+发送方的len。
    (2).三次握手时,客户端、服务端握手时,len=0,对方ack=seq+1。
    而数据传输过程时,len=0,对方ack=seq+0

  • 相关阅读:
    基于Xml方式Bean的配置-beanName个别名配置
    C++中函数原型和函数定义
    语音控制-循迹跟随避障前进后退左转右转
    双向长短期记忆网络(BiLSTM)详解
    LeetCode中等题题解思路+源码合集(持续更新中)
    语义分割生成混淆矩阵
    Rust认识所有权(4)
    STM32个人笔记-程序跑飞
    I2C 子系统(二):I3C spec
    基于STM32设计的智慧农业管理系统(ESP8266+腾讯云微信小程序)
  • 原文地址:https://blog.csdn.net/sishen4199/article/details/133783995