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技術ブログ