TCP全连接队列与tcpdump抓包

TCP 相关实验

理解 listen 的第⼆个参数

• 基于刚才封装的 TcpSocket 实现以下测试代码

• 对于服务器, listen 的第⼆个参数设置为 1, 并且不调⽤ accept

• 测试代码链接:https://gitee.com/whb-helloworld/linux-plus-meal/tree/master/testbacklog

test_server.cc

cpp 复制代码
#include "tcp_socket.hpp"
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("Usage ./test_server [ip] [port]\n");
        return 1;
    }
    TcpSocket sock;
    bool ret = sock.Bind(argv[1], atoi(argv[2]));
    if (!ret)
    {
        return 1;
    }
    ret = sock.Listen(2);
    if (!ret)
    {
        return 1;
    }
    // 客⼾端不进⾏ accept
    while (1)
    {
        sleep(1);
    }
    return 0;
}

test_client.cc

cpp 复制代码
#include "tcp_socket.hpp"
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        printf("Usage ./test_client [ip] [port]\n");
        return 1;
    }
    TcpSocket sock;
    bool ret = sock.Connect(argv[1], atoi(argv[2]));
    if (ret)
    {
        printf("connect ok\n");
    }
    else
    {
        printf("connect failed\n");
    }
    while (1)
    {
        sleep(1);
    }
    return 0;
}

此时启动 3 个客⼾端同时连接服务器, ⽤ netstat 查看服务器状态, ⼀切正常.

但是启动第四个客⼾端时, 发现服务器对于第四个连接的状态存在问题了

bash 复制代码
tcp 3 0 0.0.0.0:9090 0.0.0.0:* LISTEN 
9084/./test_server 
tcp 0 0 127.0.0.1:9090 127.0.0.1:48178 SYN_RECV 
- 
tcp 0 0 127.0.0.1:9090 127.0.0.1:48176 
ESTABLISHED - 
tcp 0 0 127.0.0.1:48178 127.0.0.1:9090 
ESTABLISHED 9140/./test_client 
tcp 0 0 127.0.0.1:48174 127.0.0.1:9090 
ESTABLISHED 9087/./test_client 
tcp 0 0 127.0.0.1:48176 127.0.0.1:9090 
ESTABLISHED 9088/./test_client 
tcp 0 0 127.0.0.1:48172 127.0.0.1:9090 
ESTABLISHED 9086/./test_client 
tcp 0 0 127.0.0.1:9090 127.0.0.1:48174 
ESTABLISHED - 
tcp 0 0 127.0.0.1:9090 127.0.0.1:48172 
ESTABLISHED - 

客⼾端状态正常, 但是服务器端出现了 SYN_RECV 状态, ⽽不是 ESTABLISHED 状态

这是因为, Linux内核协议栈为⼀个tcp连接管理使⽤两个队列:

  1. 半链接队列(⽤来保存处于SYN_SENT和SYN_RECV状态的请求)

  2. 全连接队列(accpetd队列)(⽤来保存处于established状态,但是应⽤层没有调⽤accept取⾛的请求)

⽽全连接队列的⻓度会受到 listen 第⼆个参数的影响.

全连接队列满了的时候, 就⽆法继续让当前连接的状态进⼊ established 状态了.

这个队列的⻓度通过上述实验可知, 是 listen 的第⼆个参数 + 1.

使⽤TCP dump进⾏抓包,分析TCP过程

测试的时候要注意,注意和代码结合哦,我们代码中故意在close(sockfd)哪⾥留了⼀个问题

TCPDump 是⼀款强⼤的⽹络分析⼯具,主要⽤于捕获和分析⽹络上传输的数据包。

安装 tcpdump

tcpdump通常已经预装在⼤多数 Linux 发⾏版中。如果没有安装,可以使⽤包管理器进⾏安装。例如 Ubuntu,可以使⽤以下命令安装:

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

在 Red Hat 或 CentOS 系统中,可以使⽤以下命令:

bash 复制代码
sudo yum install tcpdump 

常⻅使⽤

1. 捕获所有⽹络接⼝上的 TCP 报⽂

使⽤以下命令可以捕获所有⽹络接⼝上传输的 TCP 报⽂:

bash 复制代码
$ sudo tcpdump -i any tcp 

注意: -i any 指定捕获所有⽹络接⼝上的数据包, tcp 指定捕获 TCP 协议的数据包。 i 可以理解成为 interface 的意思

2. 捕获指定⽹络接⼝上的 TCP 报⽂

如果你只想捕获某个特定⽹络接⼝(如 eth0)上的 TCP 报⽂,可以使⽤以下命令:

bash 复制代码
$ 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 
$ sudo tcpdump -i eth0 tcp

3. 捕获特定源或⽬的 IP 地址的 TCP 报⽂

使⽤ host 关键字可以指定源或⽬的 IP 地址。例如,要捕获源 IP 地址为 192.168.1.100TCP 报⽂,可以使⽤以下命令:

bash 复制代码
$ sudo tcpdump src host 192.168.1.100 and tcp 

要捕获⽬的 IP 地址为 192.168.1.200 TCP 报⽂,可以使⽤以下命令:

bash 复制代码
$ sudo tcpdump dst host 192.168.1.200 and tcp 

同时指定源和⽬的 IP 地址,可以使⽤ and 关键字连接两个条件:

bash 复制代码
$ sudo tcpdump src host 192.168.1.100 and dst host 192.168.1.200 and tcp

4. 捕获特定端⼝的 TCP 报⽂

使⽤ port 关键字可以指定端⼝号。例如,要捕获端⼝号为 80 的 TCP 报⽂(通常是 HTTP 请求),可以使⽤以下命令:

bash 复制代码
$ sudo tcpdump port 80 and tcp 

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

使⽤ -w 选项可以将捕获的数据包保存到⽂件中,以便后续分析。例如:

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

这将把捕获到的 HTTP 流量保存到名为 data.pcap 的⽂件中。

• 了解:pcap后缀的⽂件通常与PCAP(Packet Capture)⽂件格式相关,这是⼀种⽤于捕获⽹络数据包的⽂件格式

6. 从⽂件中读取数据包进⾏分析

使⽤ -r 选项可以从⽂件中读取数据包进⾏分析。例如:

bash 复制代码
tcpdump -r data.pcap 

这将读取 data.pcap ⽂件中的数据包并进⾏分析。

注意事项

• 使⽤ tcpdump时,请确保你有⾜够的权限来捕获⽹络接⼝上的数据包。通常,你需要以 root ⽤⼾⾝份运⾏ tcpdump。

• 使⽤tcpdump的时候,有些主机名会被云服务器解释成为随机的主机名,如果不想要,就⽤-n选项

• 主机观察三次握⼿的第三次握⼿,不占序号

使⽤ wireshark 分析 TCP 通信流程(了解)

wireshark是 windows 下的⼀个⽹络抓包⼯具. 虽然 Linux 命令⾏中有 tcpdump ⼯具同样能完成抓

包, 但是 tcpdump 是纯命令⾏界⾯, 使⽤起来不如 wireshark ⽅便.

下载 wireshark

https://1.na.dl.wireshark.org/win64/Wireshark-win64-2.6.3.exe

或者

链接:https://pan.baidu.com/s/159UUIoZ8b7guWDeuAHoF9A

提取码:k79r

安装 wireshark

直接双击安装, 没啥太多注意的.

启⽤ telnet 客⼾端

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

启动 wireshark 并设置过滤器

由于机器上的⽹络数据报可能较多, 我们只需要关注我们需要的. 因此需要设置过滤器

在过滤器栏中写⼊

bash 复制代码
ip.addr == [服务器 ip] 

则只抓取指定ip的数据包.

或者在过滤器中写⼊

bash 复制代码
tcp.port == 9090 

则只关注 9090 端⼝的数据

更多过滤器的设置, 参考

https://blog.csdn.net/donot_worry_be_happy/article/details/80786241

观察三次握⼿过程

启动好服务器.

使⽤ telnet 作为客⼾端连接上服务器

bash 复制代码
telnet [ip] [port] 

抓包结果如下:

观察三个报⽂各⾃的序列号和确认序号的规律.

在中间部分可以看到 TCP 报⽂详细信息

观察确认应答

在 telnet 中输⼊⼀个字符

可以看到客⼾端发送⼀个⻓度为 1 字节的数据, 此时服务器返回了⼀个 ACK 以及⼀个 9 个字节的响应(捎带应答), 然后客⼾端再反馈⼀个 ACK(注意观察 序列号和确认序号)

观察四次挥⼿

在 telnet 中输⼊ ctrl + ], 回到 telnet 控制界⾯, 输⼊ quit 退出

实际上是 "三次挥⼿", 由于捎带应答, 导致其中的两次重合在了⼀起.

注意事项

如果使⽤虚拟机部署服务器, 建议使⽤ "桥接⽹卡" 的⽅式连接⽹络. NAT ⽅式下由于进⾏了 ip 和 port 的替换.

使⽤云服务器测试, 更加直观⽅便.

附录:

相关推荐
cheems95279 小时前
【javaEE】全方位拆解 UDP 协议
网络·网络协议·udp
Luck_ff08109 小时前
百度指数数据采集与可视化平台 BaiduIndexHunter
github·开源软件
崎岖Qiu9 小时前
【计算机网络 | 第七篇】数据链路层及三个基本问题
网络·网络协议·计算机网络·数据链路层
科技块儿9 小时前
物联网设备分布分析需要精准地理信息?支持IPv4IPv6双栈批量解析的IP离线库
物联网·网络协议·tcp/ip
Yu_Lijing9 小时前
网络复习篇——网络基础(一)
网络·c++·笔记
乾元9 小时前
身份与访问:行为生物识别(按键习惯、移动轨迹)的 AI 建模
运维·网络·人工智能·深度学习·安全·自动化·安全架构
阿里嘎多学长9 小时前
2026-02-03 GitHub 热点项目精选
开发语言·程序员·github·代码托管
tzy2339 小时前
通俗理解 TCP 的 三次握手 和 四次挥手
网络·tcp/ip·三次握手·四次挥手