PostgreSQL 流量分析 - Wireshark - 客户端总共接收了多少字节?

PostgreSQL 流量分析 - Wireshark - 客户端总共接收了多少字节?

<TL;DR> 正在接收多少字节总共SELECT *针对(小)表发出命令时?
</TL;DR>

我有一张 PostgreSQL 表 - 非常简单(参见 fiddle这里):

CREATE TABLE test
(
  a INT NOT NULL,
  b TEXT NOT NULL
);

已填充:

INSERT INTO test VALUES
(1, 'afasdfasdf'),
(2, 'afasdfasdafasdfasf'),
(3, 'afasdfasdfasdfasdfsdf'),
(4, 'af'),
(5, 'afasdfa'),
(6, '我爱你');

并运行此查询

SELECT
  SUM(PG_COLUMN_SIZE(temp.a))     AS int_sz,
  SUM(CHARACTER_LENGTH(temp.b))   AS char_len,
  SUM(OCTET_LENGTH(temp.b))       AS oct_len,
  SUM(OCTET_LENGTH(temp.*::TEXT)) AS oct_len_total
FROM
  (SELECT * FROM test) AS temp;

给出结果:

int_sz  char_len  oct_len  oct_len_total
    24        61       67             91

因此,我们可以看到char_len!= oct_len(每个汉字占用 3 个字节 - UTF8)——所以字节的总长度为 91——很好。

然后我用这个文章设置 wireshark 客户端来监控psql(PostgreSQL 命令行客户端)流量。我首先启动数据库并登录,以便此流量(握手、数据库启动消息等)不会出现在 wireshark 日志中。然后我运行(以 root 身份在另一个终端窗口中):

tshark -i any -f 'tcp port 5432' -d tcp.port==5432,pgsql -O pgsql

并在psql窗口中发出命令(此时我应该提到,我不确定这些Frame命令是否来自客户端或者服务器,但就我的目的而言,这并不重要——我只是想知道数据总量已传输):

SELECT * FROM test;

wireshark 日志中出现以下内容:

Frame 1: 93 bytes on wire (744 bits), 93 bytes captured (744 bits) on interface any, id 0
Linux cooked capture v1
Internet Protocol Version 4, Src: 192.168.234.75, Dst: 192.168.234.75
Transmission Control Protocol, Src Port: 30050, Dst Port: 5432, Seq: 1, Ack: 1, Len: 25
PostgreSQL
    Type: Simple query
    Length: 24
    Query: SELECT * FROM test;

现在查询字符串本身的长度为 19 个字节。但是,我有:

  • 线路上 93 字节
  • 莱恩 25
  • 长度 24

在这种情况下,数据总量是多少(我很确定 - 由客户端传输) - 不同数字的含义是什么?

之后Frame 1,我们Frame 2在wireshark日志中看到:

Frame 2由两部分组成,一个标题,然后是各个行的行数据(相当确定这是由客户端接收并由服务器传输的)。

标头:

Frame 2: 298 bytes on wire (2384 bits), 298 bytes captured (2384 bits) on interface any, id 0
Linux cooked capture v1
Internet Protocol Version 4, Src: 192.168.234.75, Dst: 192.168.234.75
Transmission Control Protocol, Src Port: 5432, Dst Port: 30050, Seq: 1, Ack: 26, Len: 230
PostgreSQL
    Type: Row description
    Length: 46
    Field count: 2
        Column name: a
            Table OID: 24583
            Column index: 1
            Type OID: 23
            Column length: 4      -- The length of an INT - 4 bytes.
            Type modifier: -1
            Format: Text (0)
        Column name: b
            Table OID: 24583
            Column index: 2
            Type OID: 25
            Column length: -1  -- means it's a TEXT field with no specified length
            Type modifier: -1
            Format: Text (0)

因此,标头包含298 bytes on wire,并且Len: 230- 因此,这似乎是客户端从服务器接收的总数据的摘要。这是正确的吗?

总数是 298 还是 230 - 相对于表格本身的 91?请解释一下这些数字,我们将不胜感激。

两行数据:

First row:

PostgreSQL
    Type: Data row
    Length: 25
    Field count: 2
        Column length: 1   -- an INT (i.e. test.a) is 4 bytes - why 1?
        Data: 31
        Column length: 10   -- corresponds exactly to the size of the TEXT column (i.e. test.b in fiddle) in bytes
        Data: 61666173646661736466

Length:25、31Data:Column Length:1,第二个的长度Data:是20个字符?

这些数字代表什么意思?

Second row:

PostgreSQL
    Type: Data row
    Length: 33
    Field count: 2
        Column length: 1
        Data: 32
        Column length: 18   -- corresponds exactly to the size of the column (t.b) in bytes
        Data: 616661736466617364616661736466617366
...
... snipped for brevity - see bottom of post for the other 4 records.
...

与第 1 行的问题相同——究竟收到了什么?

在第 2 帧结束时,我们有以下内容(清理/握手?):

PostgreSQL
    Type: Command completion
    Length: 13
    Tag: SELECT 6

服务器告诉客户端,数据传输完毕?还有:

PostgreSQL
    Type: Ready for query
    Length: 5
    Status: Idle (73)

服务器告诉客户端,它已准备好执行更多工作?并且此Frame 3部分出现在每个命令之后:

Frame 3: 68 bytes on wire (544 bits), 68 bytes captured (544 bits) on interface any, id 0
Linux cooked capture v1
Internet Protocol Version 4, Src: 192.168.234.75, Dst: 192.168.234.75
Transmission Control Protocol, Src Port: 30050, Dst Port: 5432, Seq: 26, Ack: 231, Len: 0

那么,客户端运行命令时接收的数据总量SELECT是 3 帧的总和吗bytes on wire?还是不同的数字?

如能提供任何解释、资源指针、URL、参考资料等,我们将不胜感激。

====================== 上面的 wireshark 日志摘录中未包含 4 条记录 ===========

PostgreSQL
    Type: Data row
    Length: 36
    Field count: 2
        Column length: 1
        Data: 33
        Column length: 21
        Data: 616661736466617364666173646661736466736466
PostgreSQL
    Type: Data row
    Length: 17
    Field count: 2
        Column length: 1
        Data: 34
        Column length: 2
        Data: 6166
PostgreSQL
    Type: Data row
    Length: 22
    Field count: 2
        Column length: 1
        Data: 35 
        Column length: 7
        Data: 61666173646661
PostgreSQL
    Type: Data row
    Length: 24
    Field count: 2
        Column length: 1
        Data: 36
        Column length: 9   -- 3 Chinese character = 9 bytes, i.e. 3 per character
        Data: e68891e788b1e4bda0

答案1

在这种情况下,数据总量是多少(我很确定 - 由客户端传输) - 不同数字的含义是什么?

不同数字的含义是有效载荷大小在每一层。您有一个 Postgres 协议数据包,指示其自己的有效负载长度(标签/长度/有效负载格式,显然带有一个未计算的 1 字节“类型”标签头),并且这些数据包中的几个进入指示其自己的有效负载长度的 TCP 段,并且该 TCP 段(带有其标头)进入指示其自身长度的 IP 数据包,并且该 IP 数据包进入 Wireshark 指示其全长的以太网帧。

Ethernet frame [93]
 ├─ Ethernet header [always 14]
 └─ Payload: IPv4 packet [79]
     ├─ IPv4 header [usually 20]
     └─ Payload: TCP segment [59]
         ├─ TCP segment header [34? (20 + options)]
         └─ Payload: Postgres data [25]
             ├─ Postgres packet [25]
             │   ├─ Tag field (packet type) [1]
             │   ├─ Length field       ┐ (range of the
             │   └─ Data field         ┘  "Length" field)
             ├─ (same TCP segment could have than one Postgres packet)
             └─ (etc)

并在 psql 窗口中发出命令(我应该在此时提到,我不确定帧是来自客户端还是服务器,但就我的目的而言,这并不重要 - 我只想知道传输的总数据量):

从技术上讲,“帧长度”可以告诉你客户端计算机最终接收的字节数,当同一个 IP 数据包跨不同的链路类型时,帧开销会逐跳变化(例如,Wi-Fi 连接的客户端将产生与以太网连接的服务器接收的长度不同的帧)。

只有帧有效负载(IP 数据包)在整个路径上保持不变,因此通常后者的测量更有意义。

Wireshark 不会在其摘要中报告 IP 数据包(帧有效负载)的大小,而且它似乎没有一个字段可以直接提供该信息,因此您必须专门向它询问ip.lenipv6.plen字段。(然而,这两者有一个重要的区别;ip.len对于 IPv4,IPv6 包括 IP 标头本身,而ipv6.plenIPv6 则不包括,因此您必须向后者添加固定的 40 个字节。)

例如,要获取单个字段(包括 ip.version 以允许计算 IPv6 的完整长度):

tshark -i wlan0 -T fields -e ip.version -e ip.len -e ipv6.plen

列长度​​:1 - INT(即 test.a)是 4 个字节 - 为什么是 1?

数据包格式不必与存储格式相同。如果值适合 1 个字节,Postgres 显然会将其传输为 1 个字节 - 无论是否包含前导零,它仍然是相同的整数。

    Column length: 10   -- corresponds exactly to the size of the TEXT column (i.e. test.b in fiddle) in bytes
   Data: 61666173646661736466

长度:25,数据:31 和列长度:1,第二个数据的长度:是 20 个字符?

Wireshark 正在向您显示 20十六进制数字,而不是 20 个字符。一个十六进制数字代表四位,因此每个数字代表一个字节,为您提供 10 个字节的实际数据。

Wireshark 的“数据包树”输出是为了便于阅读,不是为了精确。此时我建议将捕获的数据加载到图形化的 Wireshark 中,这样您就可以单击数据包树中的每个字段,并查看“原始字节”窗格中突出显示的相应字节 - 这会告诉您例如“列长度”本身是否占用 1 个字节、2 个或 4 个字节,或者“数据”字段是 ASCII 还是十六进制字节、整数还是其他内容。

相关内容