hana_shinのLinux技術ブログ

Linuxの技術情報を掲載しています。特にネットワークをメインに掲載していきます。

ssコマンドのRecv-Q,Send-Qの意味について(ESTABLISHED状態のとき)



1 はじめに

ssコマンドを実行すると、Recv-QとSend-Q という項目が表示されます。本記事では、Recv-QとSend-Qの意味について説明します。なお、ssコマンドの使い方は、ssコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# ss -antpo4
State          Recv-Q         Send-Q                  Local Address:Port                   Peer Address:Port          Process
LISTEN         0              128                           0.0.0.0:22                          0.0.0.0:*              users:(("sshd",pid=842,fd=5))
ESTAB          0              0                      192.168.122.68:22                    192.168.122.1:51132          users:(("sshd",pid=1504,fd=5),("sshd",pid=1486,fd=5)) timer:(keepalive,49min,0)

それぞれの意味は以下になります。ESTABLISHED状態とLISTEN状態では意味が異なります。ここでは、ESTABLISHED状態のときのRecv-Q,Send-Qの意味について確認してみます。

項目 意味
Recv-Q ソケットの受信バッファに残っている受信データのバイト数を表します。ユーザプロセスがソケットの受信バッファから受信データを全て読み出すと0になります
Send-Q ソケットの送信バッファに残っている送信データのバイト数を表します。送信データに対してACKが返ると、送信バッファに残っている送信データが削除されます。送信データを全て削除すると0になります

LISTEN状態のときのRecv-Q,Send-Qの意味についは、ssコマンドのRecv-Q,Send-Qの意味について(LISTEN状態のとき) - hana_shinのLinux技術ブログを参照してください。

2 検証環境

2.1 ネットワーク構成

サーバとクライアントの2台構成です。図中のeth0はNICの名前です。

                               192.168.122.0/24
client(eth0) ---------------------------------------------------- (eth0) server
            .177                                               .68

2.2 版数

サーバとクライアントのAlmaLinuxの版数は以下のとおりです。

[root@server ~]# cat /etc/redhat-release
AlmaLinux release 8.6 (Sky Tiger)

カーネル版数は以下のとおりです。

[root@server ~]# uname -r
4.18.0-372.9.1.el8.x86_64

3 事前準備

クライアントからサーバの11111番ポートにアクセスできるようにするため、TCPの11111番ポートを解放します。なお、firewall-cmdコマンドの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# firewall-cmd --add-port=11111/tcp

設定を確認します。TCPの11111番ポートへのアクセスを許可するルールが追加されたことがわかります。

[root@server ~]# firewall-cmd --list-ports
11111/tcp

4 Recv-Qの確認

サーバでncコマンドを実行します。なお、ncコマンドのインストール方法、使い方は、ncコマンドの使い方(ネットワーク実験の幅が広がるなぁ~) - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# nc -kl 11111

送信データのデータ長(TCPペイロード長)を確認するため、tsharkコマンドを実行します。なお、tsharkコマンドのインストール方法、使い方は、tsharkコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# tshark -i eth0 -n -Y 'tcp.port==11111'

ncコマンドを実行すると、サーバ/クライアント間でTCPコネクションが確立されます。

[root@client ~]# nc 192.168.122.68 11111

サーバでssコマンドを実行すると、サーバ/クライアント間でTCPコネクションが確立され、Recv-Qの値が0であることがわかります(一番下の行)。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     0         0              192.168.122.68:11111         192.168.122.177:59746

Ctrl+zを押下して、ncプロセスを停止状態にします。ncプロセスを停止する理由は、ncプロセスがソケットの受信バッファから受信データを読み出さないようにするためです。

[root@server ~]# nc -kl 11111
^Z
[1]+  停止                  nc -kl 11111

psコマンドを実行すると、ncプロセスの状態が停止状態(STAT列がT)になっていることがわかります。なお、psコマンドの使い方は、psコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。

[root@server ~]# ps -C nc -o comm,pid,stat
COMMAND             PID STAT
nc                 1473 T

クライアントで12345と入力したあと、Enterキーを押下します。改行コードも含めて6バイト入力することになります。

[root@client ~]# nc 192.168.122.68 11111
12345

tsharkの実行結果を確認すると、クライアントからサーバに6バイト(Len=6)送信されていることがわかります。

[root@server ~]# tshark -i eth0 -n -Y 'tcp.port==11111'
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
 1481 2624.783047786 192.168.122.177 → 192.168.122.68 TCP 72 59742 → 11111 [PSH, ACK] Seq=1 Ack=1 Win=229 Len=6 TSval=515145826 TSecr=1559586379
 1482 2624.783147350 192.168.122.68 → 192.168.122.177 TCP 66 11111 → 59742 [ACK] Seq=1 Ack=7 Win=227 Len=0 TSval=1562229283 TSecr=515145826

サーバでssコマンドを実行すると、Recv-Qの値が6になっていることがわかります。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     6         0              192.168.122.68:11111         192.168.122.177:59742

fgコマンドを実行して、停止しているncプロセスを再開します。

[root@server ~]# fg
nc -kl 11111

ncプロセスを再開すると、ncプロセスがソケットの受信バッファから受信データを読み出すので、Recv-Qの値が6から0になったことがわかります。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     0         0              192.168.122.68:11111         192.168.122.177:59746

5 Send-Qの確認

サーバでncコマンドを実行します。

[root@server ~]# nc -kl 11111

クライアントでncコマンドを実行すると、サーバ/クライアント間でTCPコネクションが確立されます。

[root@client ~]# nc 192.168.122.68 11111

サーバでssコマンドを実行すると、サーバ/クライアント間でTCPコネクションが確立され、Send-Qの値が0であることがわかります(一番下の行)。そして、ソケットの送信バッファに送信データが残っていないことになります。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     0         0              192.168.122.68:11111         192.168.122.177:59750

クライアントでiptablesコマンドを実行します。このとき、クライアントからサーバへのACKパケットを廃棄する設定をします。

[root@client ~]# iptables -I OUTPUT -p tcp --dport 11111 --tcp-flags ALL ACK -j DROP

設定を確認すると、OUTPUTチェインの先頭(1番目)にACKパケットを廃棄する設定がされていることがわかります。

[root@client ~]# iptables -nvL OUTPUT --line-numbers
Chain OUTPUT (policy ACCEPT 216 packets, 25829 bytes)
num   pkts bytes target     prot opt in     out     source               destination       
1        0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:11111 flags:0x3F/0x10

サーバで12345と入力したあと、Enterキーを押下します。改行コードも含めて6バイト入力することになります。

[root@server ~]# nc -kl 11111
12345

サーバでssコマンドを実行します。サーバからクライアントに送信したデータに対してACKを受信できないので、ソケットの送信バッファに送信データが(6バイト)残ったままになっていることがわかります。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     0         6              192.168.122.68:11111         192.168.122.177:59750

クライアントでiptablesコマンドを実行します。OUTPUTチェインの統計情報を確認すると、ACKパケットを9個廃棄していることがわかります。廃棄した9個のACKパケットの内訳ですが、1つは最初にサーバからクライアントに送信したデータに対するACKパケット、残りはサーバからクライアントへの再送データに対するACKパケットです。なお、iptablesコマンドの実行タイミングによって、ACKパケットの廃棄数は異なります。

[root@client ~]# iptables -nvL OUTPUT --line-numbers
Chain OUTPUT (policy ACCEPT 226 packets, 27413 bytes)
num   pkts bytes target     prot opt in     out     source               destination       
1        9   564 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:11111 flags:0x3F/0x10

ACKパケットを廃棄するルールを削除します。なお、引数に指定している1は、1番目のルールを意味しています。

[root@client ~]# iptables -D OUTPUT 1

OUTPUTのルールを確認します。設定したルールが削除されたことがわかります。

[root@client ~]# iptables -nvL OUTPUT --line-numbers
Chain OUTPUT (policy ACCEPT 257 packets, 30621 bytes)
num   pkts bytes target     prot opt in     out     source               destination       

ACKパケット廃棄のルールを削除すると、Send-Q の値が0になることがわかります。

[root@server ~]# ss -na4 'sport == :11111'
Netid    State     Recv-Q    Send-Q          Local Address:Port             Peer Address:Port     Process
tcp      LISTEN    0         1                     0.0.0.0:11111                 0.0.0.0:*
tcp      ESTAB     0         0              192.168.122.68:11111         192.168.122.177:59750

Z 参考情報

私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ