07-网络篇-抓包分析TCP

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

##1.程序

客户端:

vs_client.cpp

cpp 复制代码
#include "stdafx.h"
#include <iostream>
#include <winsock2.h>
#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;
}

服务端:

sever.c

cpp 复制代码
#include <unistd.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>

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;
}

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

bash 复制代码
$ 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

##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

相关推荐
linux修理工5 分钟前
n1 armbian 安装桌面环境并启用xrdp远程登录
linux·服务器·数据库
花小璇学linux21 分钟前
imx6ull-裸机学习实验1——汇编LED灯实验
linux·汇编·imx6ull·arm裸机开发
Brookty32 分钟前
【操作系统】进程(二)内存管理、通信
java·linux·服务器·网络·学习·java-ee·操作系统
sanggou5 小时前
Linux批量执行工具脚本使用指南:一键运行多个release-dev.sh脚本
linux·bash
牧以南歌〆9 小时前
在Ubuntu主机中修改ARM Linux开发板的根文件系统
linux·arm开发·驱动开发·ubuntu
夜月yeyue10 小时前
设计模式分析
linux·c++·stm32·单片机·嵌入式硬件
kfepiza10 小时前
Debian的`/etc/network/interfaces`的`allow-hotplug`和`auto`对比讲解 笔记250704
linux·服务器·网络·笔记·debian
cuijiecheng201811 小时前
Ubuntu下布署mediasoup-demo
linux·运维·ubuntu
独行soc13 小时前
2025年渗透测试面试题总结-2025年HW(护网面试) 33(题目+回答)
linux·科技·安全·网络安全·面试·职场和发展·护网
java龙王*14 小时前
开放端口,开通数据库连接权限,无法连接远程数据库 解决方案
linux