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

相关推荐
Justin_191 分钟前
Linux-Shell编程之sed和awk
linux·运维·服务器
Akshsjsjenjd4 分钟前
深入理解 Shell 循环与函数:语法、示例及综合应用
linux·运维·自动化·shell
塔中妖23 分钟前
【华为OD】Linux发行版的数量
linux·算法·华为od
半桔1 小时前
【Linux手册】消息队列从原理到模式:底层逻辑、接口实战与责任链模式的设计艺术
java·linux·运维·服务器
华纳云IDC服务商1 小时前
Linux服务器的系统安全强化超详细教程
linux·服务器·系统安全
衍余未了1 小时前
k8s镜像推送到阿里云,使用ctr推送镜像到阿里云
linux·运维·服务器
yiqiqukanhaiba1 小时前
Linux编程笔记1-概念&数据类型&输入输出
linux·运维·服务器
乌萨奇也要立志学C++2 小时前
【Linux】进程概念(一):从冯诺依曼体系到 PCB 的进程核心解析
linux·运维·服务器
JAVA数据结构2 小时前
Linux 运维常用命令详解
linux
huangyuchi.2 小时前
【Linux系统】初见线程,概念与控制
linux·运维·服务器·页表·linux线程概念·linux线程控制·分页式存储管理