TCP全连接队列与抓包

再谈三次握手

1. 函数调用与包的对应关系

  • 客户端调用 connect () :
    • 触发动作 :这是唯一一个由应用层显式触发握手包的动作。调用 connect 后,内核会发送第一个 SYN 包,进入SYN_SENT。
    • 等待 : connect 会阻塞,直到收到服务器的 SYN+ACK 并发送最后的 ACK 后(即三次握手完成), connect 才会返回成功,客户端进入ESTABLISHED状态。
  • 服务端调用 listen () :
    • 触发动作 :它不发包,但它告诉内核:"我已经准备好了,请帮我建立半连接队列和全连接队列,并开始监听端口。"
  • 服务端调用 accept () :
    • 触发动作 : 它不触发任何握手包的发送!
    • 真实作用 :它的作用是从 全连接队列 (已经完成握手的连接)中 "拎" 出一个已经成功的连接,返回一个新的 socket fd 给应用层使用。
    • 如果队列为空 : accept 会一直阻塞,直到全连接队列里有连接为止。

2. SYN 的应答是自动的吗?

是的,应答是完全自动的。

当客户端的 SYN 包到达服务器网卡时:

  1. 内核检查 :内核查看该端口是否已经调用了 listen () 。
  2. 自动回复 :如果端口在监听,内核会 自动 回复一个 SYN+ACK ,并将该连接信息放入 半连接队列 。
  3. 无需 accept :哪怕你的程序还没运行到 accept () 这一行,或者你的程序因为 CPU 太忙卡住了,只要内核还在运行,这个 SYN+ACK 就会自动发出去。

3. 半连接队列 vs 全连接队列

队列名称 别名 状态 什么时候进入 什么时候离开
半连接队列 SYN Queue SYN_RECV 收到客户端的 SYN 收到客户端最后的 ACK
全连接队列 Accept Queue ESTABLISHED 收到最后的 ACK (握手完成) 应用层调用 accept ()

流转过程:

  1. SYN 到达 :内核回复 SYN+ACK ,连接进入 半连接队列 。
  2. ACK 到达 :三次握手完成,内核将连接从半连接队列移出,放入 全连接队列 。
  3. 应用层动作 :你的代码调用 accept () ,内核从全连接队列头部取出一个连接交给你的程序。

4. QA

  • accept 的调用发送了什么?
    • 什么都没发。它只是在 "收割" 成果(从全连接队列取走建立好的连接)。
  • 给客户端 SYN 的应答是自动发送的吗还是 accept 导致的?
    • 是内核 自动发送 的,与 accept 无关。只要你调用了 listen ,内核协议栈就会接管握手逻辑。
  • 全连接与半连接队列的区别?
    • 半连接队列是 "握手中" 的半成品;
    • 全连接队列是 "已完工" 的成品,等待被 accept 消费。

5. 如果队列满了会怎样?

  • 半连接队列满 :通常是因为遭遇了 SYN Flood 攻击 (只发 SYN 不发最后的 ACK)。
  • 全连接队列满 :说明你的程序处理速度太慢,调用 accept () 的频率跟不上连接进来的速度。此时内核可能会直接丢弃连接或回复 RST 。这也是为什么 listen (fd, backlog) 中的 backlog 参数很重要的原因。

6 listen() 函数

首先看函数原型,建立基础认知:

复制代码
#include <sys/socket.h>
// 返回值:成功返回0,失败返回-1
int listen(int sockfd, int backlog);
  • sockfd:你已经创建并绑定(bind())了端口的监听套接字
  • backlog全连接队列的最大长度上限-1

Linux下的抓包

TCPDump 是一款强大的网络分析工具,主要用于捕获和分析网络上传输的数据包。

安装 tcpdump

tcpdump 通常已经预装在大多数 Linux 发行版中。如果没有安装,可以使用包管理器进行安装。

Ubuntu 系统

复制代码
sudo apt-get update
sudo apt-get install tcpdump

Red Hat / CentOS 系统

复制代码
sudo yum install tcpdump

常见使用

1. 捕获所有网络接口上的 TCP 报文

使用以下命令可以捕获所有网络接口上传输的 TCP 报文:

复制代码
$ sudo tcpdump -i any tcp

注意:-i any 指定捕获所有网络接口上的数据包,tcp 指定捕获 TCP 协议的数据包。i 可以理解为 interface 的缩写。

2. 捕获指定网络接口上的 TCP 报文

若只需捕获某个特定网络接口(如 eth0)的 TCP 报文,先通过 ifconfig 查看网络接口信息,再执行捕获命令:

复制代码
# 查看网络接口信息
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.45.153 netmask 255.255.192.0 broadcast 172.18.63.255
inet6 fe80::216:3eff:fe03:959b prefixlen 64 scopeid 0x20<link>
ether 00:16:3e:03:95:9b txqueuelen 1000 (Ethernet)
RX packets 34367847 bytes 9360264363 (9.3 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 34274797 bytes 6954263329 (6.9 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

# 捕获 eth0 接口的 TCP 报文
$ sudo tcpdump -i eth0 tcp

3. 捕获特定源 / 目的 IP 地址的 TCP 报文

使用 host 关键字指定 IP 地址,结合 src(源)/dst(目的)限定方向:

复制代码
# 捕获源 IP 为 192.168.1.100 的 TCP 报文
$ sudo tcpdump src host 192.168.1.100 and tcp

# 捕获目的 IP 为 192.168.1.200 的 TCP 报文
$ sudo tcpdump dst host 192.168.1.200 and tcp

# 同时指定源和目的 IP 的 TCP 报文
$ sudo tcpdump src host 192.168.1.100 and dst host 192.168.1.200 and tcp

4. 捕获特定端口的 TCP 报文

使用 port 关键字指定端口号,例如捕获 80 端口(HTTP 常用端口)的 TCP 报文:

复制代码
$ sudo tcpdump port 80 and tcp

5. 保存捕获的数据包到文件

使用 -w 选项将捕获的数据包保存为文件,便于后续分析:

复制代码
$ sudo tcpdump -i eth0 port 80 -w data.pcap

说明 :该命令将 eth0 接口 80 端口的 HTTP 流量保存到 data.pcap 文件中;.pcap 是 Packet Capture 格式的后缀,专为网络数据包捕获设计。

6. 从文件中读取数据包进行分析

使用 -r 选项读取已保存的数据包文件并分析:

复制代码
tcpdump -r data.pcap

注意事项

  1. 权限要求:使用 tcpdump 需具备足够权限,通常需以 root 用户身份运行(加 sudo)。
  2. 主机名解析:部分云服务器会将主机名解析为随机名称,若需禁用该行为,可添加 -n 选项(直接显示 IP 而非主机名)。
  3. 三次握手特性:观察 TCP 三次握手时,第三次握手的报文不占用序号。

本地访问百度首页演示

因为tcpdump默认只输出 "协议头摘要",不展示 HTTP 的具体内容。要看到明文的 HTML 数据 ,需要加 -A 参数(表示 "以 ASCII 码形式显示数据包内容")。

重新执行抓包命令(加 -A 参数):

复制代码
tcpdump host 182.61.200.110 and tcp -A

我使用telnet访问百度首页后,抓包结果如下,可以看到确实获取了百度返回的信息


windows抓包

Wireshark 是 Windows 平台下的网络抓包工具。尽管 Linux 命令行中的 tcpdump 工具也能实现抓包功能,但 tcpdump 是纯命令行界面,操作便捷性不及 Wireshark。

Wireshark 安装

https://pan.baidu.com/s/159UUIoZ8b7guWDeuAHoF9A
提取码:k79r

直接双击安装包执行安装,无特殊注意事项。

启用 Telnet 客户端

参考http:// https://jingyan.baidu.com/article/95c9d20d96ba4aec4f756154.html

启动 Wireshark 并设置过滤器

机器上的网络数据包通常较多,需通过过滤器筛选目标数据:

  • 在 Wireshark 的过滤器栏中输入规则,仅抓取指定范围的数据包
  • :抓取指定 IP 的数据包:输入 ip.addr == [目标服务器IP]
  • 抓取指定端口的数据包:输入 tcp.port == 9090(可筛选与 9090 端口相关的 TCP 数据包)。


更多过滤器的设置, 参考https://blog.csdn.net/donot_worry_be_happy/article/details/80786241

相关推荐
上海云盾-高防顾问2 小时前
CC攻击的分类与演进:从代理攻击到僵尸网络的技术剖析
网络·安全
首席拯救HMI官2 小时前
【拯救HMI】HMI容错设计:如何减少操作失误并快速纠错?
大数据·运维·前端·javascript·网络·学习
zbtlink3 小时前
一楼到四楼,如何实现Wi-Fi信号全覆盖?不同方案详解
网络·智能路由器
Ro Jace3 小时前
传统雷达信号分选方法之SDIF:Improved algorithm for the deinterleaving of radar pulses
网络·人工智能·算法
8K超高清3 小时前
CES 2026科技看点
网络·人工智能·科技·数码相机·计算机视觉
zbtlink3 小时前
怎么知道自己家里适合什么样的路由器?
网络·智能路由器
想用offer打牌3 小时前
非常好用的工具: curl
java·后端·github
复园电子3 小时前
在不重构LIMS的前提下,实现合规电子签名:一种可落地的架构与实现思路
服务器·网络·微信
汪汪大队u3 小时前
arp和免费arp的区别
网络