CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
  • 第1章高频C++11重难点知识解析

  • 第2章Linux GDB高级调试指南

  • 第3章C++多线程编程从入门到进阶

  • 第4章C++网络编程重难点解析

  • 第5章网络通信故障排查常用命令

    • 5.1 ifconfig
    • 5.2 ping
    • 5.3 telnet
    • 5.4 netstat
    • 5.5 lsof
    • 5.6 nc
    • 5.7 curl
    • 5.8 tcpdump
  • 第6章高性能网络通信协议设计精要

  • 第7章高性能服务结构设计

  • 第8章Redis 网络通信模块源码分析

  • 第9章后端服务重要模块设计探索

  • C++后端开发进阶
  • 第5章网络通信故障排查常用命令
zhangxf
2023-04-05

5.8 tcpdump

tcpdump 是 Linux 系统提供的一个非常强大的抓包工具,熟练使用它,对我们排查网络问题非常有用。如果你的机器上还没有安装,可以使用如下命令安装:

yum install tcpdump
1

如果要使用 tcpdump 命令必须具有 sudo 权限。

tcpdump 常用的选项有:

  • -i 指定要捕获的目标网卡名,网卡名可以使用前面章节中介绍的 ifconfig 命令获得;如果要抓所有网卡的上的包,可以使用 any 关键字。

    ## 抓取网卡ens33上的包
    tcpdump -i ens33
    ## 抓取所有网卡上的包
    tcpdump -i any
    
    1
    2
    3
    4
  • -X 以 ASCII 和十六进制的形式输出捕获的数据包内容,减去链路层的包头信息;-XX 以 ASCII 和十六进制的形式输出捕获的数据包内容,包括链路层的包头信息。

  • -n 不要将 ip 地址显示成别名的形式;-nn 不要将 ip 地址和端口以别名的形式显示。

  • -S 以绝对值显示包的 ISN 号(包序列号),默认以上一包的偏移量显示。

  • -vv 显示详细的抓包数据;-vvv 显示更详细的抓包数据。

  • -w 将抓取的包的原始信息(不解析,也不输出)写入文件中,后跟文件名:

     tcpdump -i any -w filename  
    
    1
  • -r 从利用 -w 选项保存的包文件中读取数据包信息。

除了可以使用选项以外,tcpdump 还支持各种数据包过滤的表达式,常见的形式如下:

## 仅显示经过端口 8888 上的数据包(包括tcp:8888和udp:8888)
tcpdump -i any 'port 8888'

## 仅显示经过端口是 tcp:8888 上的数据包
tcpdump -i any 'tcp port 8888'

## 仅显示源端口是 tcp:8888 的数据包
tcpdump -i any 'tcp src port 8888'

## 仅显示源端口是 tcp:8888 或目标端口是 udp:9999 的包 
tcpdump -i any 'tcp src port 8888 or udp dst port 9999'

## 仅显示源地址是127.0.0.1 且源端口是 tcp:9999 的包 ,以 ASCII 和十六进制显示详细输出,
## 不显示 ip 地址和端口号的别名
tcpdump -i any 'src host 127.0.0.1 and tcp src port 9999' -XX -nn -vv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

下面我们通过三个具体的操作实例来演示一下使用 tcpdump 的抓包过程。

  • 实例一 :连接一个正常的侦听端口

    假设我的服务器端的地址是 127.0.0.0.1:12345,使用 nc 命令在一个 shell 窗口创建一个服务器程序并在这个地址上进行侦听。

    nc –v -l 127.0.0.1 12345
    
    1

    效果如下图所示:

    在另外一个 shell 窗口开启 tcpdump 抓包:

    tcpdump -i any 'port 12345' -XX -nn -vv
    
    1

    效果如下:

    然后再开一个 shell 窗口,利用 nc 命令创建一个客户端去连接服务器:

    nc -v 127.0.0.1 12345
    
    1

    效果如下:

    我们抓到的包如下:

    由于我们没有在客户端和服务器之间发送任何消息,其实抓到的包就是 TCP 连接的三次握手数据包,分析如下:

    三次握手过程是客户端先给服务器发送一个 SYN,然后服务器应答一个 SYN + ACK,应答的序列号是递增 1 的,表示应答哪个请求,即从 4004096087 递增到 4004096088,接着客户端再应答一个 ACK。这个时候,我们发现发包序列号和应答序列号都变成 1了,这是 tcpdump 使用相对序号,我们加上 -S 选项后就变成绝对序列号了。

    我们按 Ctrl + C 中断 tcpdump 抓包过程,并停止用 nc 开启的客户端和服务器程序,然后在前面的 tcpdump 命令后面加上 -S 选项重新开启抓包,使用命令如下:

    tcpdump -i any 'port 12345' -XX -nn -vv -S
    
    1

    然后再按顺序用 nc 命令再次启动下服务器和客户端程序。再次得到抓包结果:

    这次得到的包的序号就是绝对序号了。

  • 实例二:连接一个不存在的侦听端口

    实例一演示的是正常的 TCP 连接三次握手过程捕获到的数据包。假如我们连接的服务器 ip 地址存在,但监听端口号不存在,我们看下 tcpdump 抓包结果。除了在一个 shell 窗口启动一个 tcpdump 抓包监测,在另外一个 shell 窗口用 nc 命令去连接一个不存在的侦听端口即可。

​ 抓包数据如下:

这个时候客户端发送 SYN,服务器应答 ACK+RST,这个应答包会导致客户端的 connect 连接失败返回。

  • 实例三:连接一个很遥远的 ip,或者网络繁忙的情形

    实际情形中,还存在一种情况就是客户端访问一个很遥远的 ip,或者网络繁忙,服务器对客户端发送的 TCP 三次握手的网络 SYN 报文没有应答,会出现什么情况呢?

    我们通过设置防火墙规则来模拟一下这种情况。使用 iptables -F 先将防火墙的已有规则都清理掉,然后给防火墙的 INPUT 链上增加一个规则:丢弃本地网卡 lo(也就是 127.0.0.1 这个回环地址)上的所有 SYN 包。

    iptables -F
    iptables -I INPUT -p tcp --syn -i lo -j DROP
    
    1
    2

    如果读者对 CentOS 的防火墙 iptables 命令有兴趣,可以使用 man iptables 在 man 手册中查看更详细的帮助。

    在开启 tcpdump 抓包之后和设置防火墙规则之后,利用 nc 命令去连接 127.0.0.1:12345 这个地址。整个过程操作效果图如下:

​ 接着,我们得到 tcpdump 抓到的数据包如下:

​

​

通过抓包数据我们可以看到:如果连接不上,一共重试了 5 次,重试的时间间隔是 1 秒,2秒,4秒,8秒,16秒,最后返回超时失败。这个重试次数在 /proc/sys/net/ipv4/tcp_syn_retries 内核参数中设置,默认为 6 。

TCP 四次挥手与三次握手基本上类似,这里就不贴出 tcpdump 抓包的详情了,强烈建议不熟悉这块的读者实际练习一遍。

上次更新: 2025/04/01, 20:53:14
5.7 curl
6.1 TCP 协议是流式协议

← 5.7 curl 6.1 TCP 协议是流式协议→

最近更新
01
第二章 关键字static及其不同用法
03-27
02
第一章 auto与类型推导
03-27
03
第四章 Lambda函数
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式