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

相关推荐
Kusunoki_D几秒前
速查 Linux 常用指令 II
linux·运维·服务器
xmweisi0221 分钟前
Ansible内置模块之 group
linux·运维·ansible·rhce·rhca·红帽认证
小猪写代码28 分钟前
Ubuntu 系统默认已安装 python,此处只需添加一个超链接即可
linux·python·ubuntu
孤寂大仙v1 小时前
【Linux笔记】——Linux线程理解与分页存储的奥秘
linux·运维·笔记
有谁看见我的剑了?2 小时前
ubuntu 22.04 wifi网卡配置地址上网
linux·运维·ubuntu
码农新猿类2 小时前
Ubuntu摄像头打开失败
linux·运维·ubuntu
PWRJOY2 小时前
Ubuntu磁盘空间分析:du命令及常用组合
linux·运维·ubuntu
ASDyushui3 小时前
Shell 编程之正则表达式与文本处理器
linux·正则表达式
zuozewei3 小时前
安全扫描之 Linux 杀毒软件 Clamav 安装
linux·运维·安全
wangchen_03 小时前
linux-信号保存和处理
linux·运维·服务器