Help us understand the problem. What is going on with this article?

ssコマンドの使い方

More than 1 year has passed since last update.

1 環境

  • 仮想マシン2台(VMware Worksation 12 player上のゲストマシン)
  • 仮想マシンのホスト名は、serverとclient
  • 仮想マシンのOSは、CentOS7.3
[root@server ~]# cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

[root@server ~]# uname -r
3.10.0-514.el7.x86_64

[root@server ~]# ss -V
ss utility, iproute2-ss130716

2 事前準備

2.1 ncコマンドのインストール

ncコマンドを使って、ssコマンドの実行結果を確認します。
あらかじめ、serverとclientにncコマンドをインストールしておきます。

[root@server ~]# yum -y install nc
[root@client ~]# yum -y install nc

2.2 ドキュメントの取得

ssのドキュメントは、man以外に、iproute-docパッケージにpsファイルがあります。
以下の方法で、psファイルをpdfファイルに変換しました。
このドキュメントには、manに記載されていない、アドレスフィルタの実施例が記載されています。

[root@client ~]# yum -y install iproute-doc
[root@client ~]# rpm -ql iproute-doc
/usr/share/doc/iproute-doc-3.10.0/ss.ps

ps2pdfを使うため、ghostscriptパッケージをインストールする。
[root@client ~]# yum -y install ghostscript

psファイルをpdfファイルに変換する。
[root@client ~]# ps2pdf /usr/share/doc/iproute-doc-3.10.0/ss.ps ss.pdf
[root@client ~]# ls ss.pdf
ss.pdf

3 ssコマンドのオプション一覧

[root@server ~]# ss -help
Usage: ss [ OPTIONS ]
       ss [ OPTIONS ] [ FILTER ]
   -h, --help          this message
   -V, --version       output version information
   -n, --numeric       don't resolve service names
   -r, --resolve       resolve host names
   -a, --all           display all sockets
   -l, --listening     display listening sockets
   -o, --options       show timer information
   -e, --extended      show detailed socket information
   -m, --memory        show socket memory usage
   -p, --processes     show process using socket
   -i, --info          show internal TCP information
   -s, --summary       show socket usage summary
   -b, --bpf           show bpf filter socket information
   -Z, --context       display process SELinux security contexts
   -z, --contexts      display process and socket SELinux security contexts
   -N, --net           switch to the specified network namespace name

   -4, --ipv4          display only IP version 4 sockets
   -6, --ipv6          display only IP version 6 sockets
   -0, --packet        display PACKET sockets
   -t, --tcp           display only TCP sockets
   -u, --udp           display only UDP sockets
   -d, --dccp          display only DCCP sockets
   -w, --raw           display only RAW sockets
   -x, --unix          display only Unix domain sockets
   -f, --family=FAMILY display sockets of type FAMILY

   -A, --query=QUERY, --socket=QUERY
       QUERY := {all|inet|tcp|udp|raw|unix|unix_dgram|unix_stream|unix_seqpacket|packet|netlink}[,QUERY]

   -D, --diag=FILE     Dump raw information about TCP sockets to FILE
   -F, --filter=FILE   read filter information from FILE
       FILTER := [ state STATE-FILTER ] [ EXPRESSION ]
       STATE-FILTER := {all|connected|synchronized|bucket|big|TCP-STATES}
         TCP-STATES := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|closed|close-wait|last-ack|listen|closing}
          connected := {established|syn-sent|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
       synchronized := {established|syn-recv|fin-wait-{1,2}|time-wait|close-wait|last-ack|closing}
             bucket := {syn-recv|time-wait}
                big := {established|syn-sent|fin-wait-{1,2}|closed|close-wait|last-ack|listen|closing}

4 TCPソケットを表示する(-t)

TCPソケットを表示するためには、-tオプションを使います。
これ以降、出力結果を見やすくするため、IPv4ソケット(4オプション指定)だけを表示します。

4.1 コネクション確立済ソケットを表示する方法

[root@client ~]# ss -t4
State      Recv-Q Send-Q             Local Address:Port               Peer Address:Port
ESTAB      0      96                  192.168.0.20:ssh                 192.168.0.6:51290

4.2 リスニングソケットを表示する方法(-l)

[root@client ~]# ss -lt4
State      Recv-Q Send-Q             Local Address:Port            Peer Address:Port
LISTEN     0      128                            *:ssh                        *:*

4.3 リスニングソケットとそれ以外のソケットを表示する方法(-a)

リスニングソケット(LISTEN)とコネクション確立済ソケット(ESTAB)が各々1つづつ表示されていることがわかる。
[root@client ~]# ss -at4
State      Recv-Q Send-Q        Local Address:Port            Peer Address:Port
LISTEN     0      128                       *:ssh                        *:*
ESTAB      0      96             192.168.0.20:ssh              192.168.0.6:51290

4.4 サービス名をポート番号で表示する方法(-n)

サービス名は、/etc/servicesに登録されています。
たとえば、sshというサービス名は22/tcp,22/udp というように登録されています。
-nを指定すると、sshというサービス名ではなく、ポート番号で表示されます。

ssコマンドを実行する。
"ssh"というサービス名ではなく、ポート番号(★印)で表示されていることがわかる。
[root@client ~]# ss -nt4
State      Recv-Q Send-Q        Local Address:Port             Peer Address:Port
ESTAB      0      96             192.168.0.20:★22              192.168.0.6:51290

4.5 ソケットを使っているプロセスを調べる方法(-p)

sshdプロセスが、コネクション確立済ソケットを使っていることがわかる(★印)。
[root@client ~]# ss -pt4
State     Recv-Q Send-Q     Local Address:Port    Peer Address:Port
ESTAB     0      96          192.168.0.20:ssh      192.168.0.6:51290     users:((★"sshd",pid=1319,fd=3))

4.6 ソケットのタイマを表示する方法(-o)

4.6.1 TIME-WAITタイマの確認方法

サーバ側でTCPコネクション確立を待つ。
[root@server ~]# nc -kl 11111

サーバの11111番ポートにTCPコネクションを確立する。
[root@client ~]# nc server 11111

Ctrl +cを押下して、クライアント側からTCPコネクションを切断する。
[root@client ~]# nc server 11111
^C

TIME-WAIT状態はアクティブクローズ側がとる状態です。TIME-WAIT状態の初期値は60秒です。
ここでは、クライアント側がTIME-WAIT状態をとるので、クライアント側でssコマンドを実行して、タイマの残り時間を確認します。
以下の例は、TCPコネクション切断から2秒経過したことを表しています(★印)。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q                                Local Address:Port            Peer Address:Port
0      0                                     192.168.0.110:51504          192.168.0.100:11111       timer:(timewait,★58sec,0)

TIME-WAIT状態の残り時間を確認する。残りが1.7秒(★)であることを表していることがわかる。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q                                Local Address:Port            Peer Address:Port
0      0                                     192.168.0.110:51504          192.168.0.100:11111       timer:(timewait,★1.744ms,0)

TIME-WAIT状態の残り時間を確認する。残りが483ミリ秒(★)であることを表していることがわかる。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q                                Local Address:Port            Peer Address:Port
0      0                                     192.168.0.110:51504          192.168.0.100:11111       timer:(timewait,★483ms,0)

TIME-WAIT状態の残り時間を確認する。60秒経過したので、TIME-WAIT状態のソケットが消滅したことがわかる。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q                                Local Address:Port            Peer Address:Port

4.7 SELinuxの情報を表示する方法(-Z,-z)

4.7.1 ソケットを使っているプロセスのセキュリティコンテキストを表示する方法(-Z)

sshdプロセスのセキュリティコンテキストが"unconfined_u:unconfined_r:unconfined_t"であることがわかる。
[root@client ~]# ss -tZ4
State      Recv-Q Send-Q      Local Address:Port       Peer Address:Port
ESTAB      0      96           192.168.0.20:ssh         192.168.0.6:51290     users:(("sshd",pid=1319,★proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,fd=3))

4.7.2 プロセスとソケットのセキュリティコンテキストを表示する方法(-z)

sshdプロセスのセキュリティコンテキスが"unconfined_u:unconfined_r:unconfined_t"、
ソケットのセキュリティコンテキストが"system_u:system_r:sshd_t"であることがわかる。
[root@client ~]# ss -tz4
State      Recv-Q Send-Q       Local Address:Port          Peer Address:Port
ESTAB      0      96            192.168.0.20:ssh            192.168.0.6:51290    users:(("sshd",pid=1319,★proc_ctx=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023,fd=3,★sock_ctx=system_u:system_r:sshd_t:s0-s0:c0.c1023))

5 UDPソケットを表示する(-u)

5.1 UDPパケットの到着を待っているソケットの確認方法(-l)

UDPパケットの到着を323番ポートで待っているソケットが1つあることがわかる。
[root@server ~]# ss -lnu4
State      Recv-Q Send-Q           Local Address:Port             Peer Address:Port
UNCONN     0      0                    127.0.0.1:323                         *:*

lsofコマンドを実行する。323番ポートはchronydが使っていることがわかる。
[root@server ~]# lsof -i:323 -P
COMMAND PID   USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
chronyd 494 chrony    1u  IPv4  16253      0t0  UDP localhost:323
chronyd 494 chrony    2u  IPv6  16254      0t0  UDP localhost:323

5.2 UDPパケット送信側のソケットを確認する方法

サーバ(server)でncコマンドを実行する。ポート番号11111で、UDPパケット到着を待ちます。
[root@server ~]# nc -lu 11111

クライアント(client)でssコマンドを実行する。まだ、11111番ポート宛てのソケットはできていない。
[root@client ~]# ss -nu4
State      Recv-Q Send-Q            Local Address:Port             Peer Address:Port

クライアント(client)でncコマンドを実行する。
[root@client ~]# nc -u server 11111

クライアント側のtera termをもう1つ起動する。
再度、クライアント(client)でssコマンドを実行する。11111番ポート宛てのソケットが生成されたことがわかる。
[root@client ~]# ss -nu4
State      Recv-Q Send-Q            Local Address:Port              Peer Address:Port
ESTAB      0      0                  192.168.0.20:46653             192.168.0.10:11111

6 アドレスフィルタで絞り込む方法

ポート番号/IPアドレスでソケットを絞り込む方法は、iproute-docパッケージに含まれている
iproute-doc-3.10.0/ss.psというファイルに説明があります。man ssには詳しい説明がありません。

6.1 ポート番号による絞り込み

---------------------------------------------------
1. 事前準備(テスト用にリスニングソケットを3つ作成する)
---------------------------------------------------
[root@server ~]# nc -l 11111&
[1] 4163
[root@server ~]# nc -l 11112&
[2] 4164
[root@server ~]# nc -l 11113&
[3] 4165
[root@server ~]# jobs
[1]   実行中               nc -l 11111 &
[2]-  実行中               nc -l 11112 &
[3]+  実行中               nc -l 11113 &

-----------------
2. 初期状態の確認
-----------------
リスニングソケットが全部で4つあることがわかる。
[root@server ~]# ss -lnt4
State      Recv-Q Send-Q             Local Address:Port                    Peer Address:Port
LISTEN     0      128                            *:22                                 *:*
LISTEN     0      10                             *:11111                              *:*
LISTEN     0      10                             *:11112                              *:*
LISTEN     0      10                             *:11113                              *:*

---------
3. 確認
---------
11112番ポートのリスニングソケットを表示する。
[root@server ~]# ss -lnt4 'sport == :11112'
State      Recv-Q Send-Q                 Local Address:Port                      Peer Address:Port
LISTEN     0      10                                 *:11112                                *:*

11112番ポート以外のリスニングソケットを表示する。
[root@server ~]# ss -lnt4 'sport != :11112'
State      Recv-Q Send-Q                 Local Address:Port                      Peer Address:Port
LISTEN     0      128                                *:22                                   *:*
LISTEN     0      10                                 *:11111                                *:*
LISTEN     0      10                                 *:11113                                *:*

11112番ポート未満のリスニングソケットを表示する。
[root@server ~]# ss -lnt4 'sport < :11112'
State      Recv-Q Send-Q                 Local Address:Port                      Peer Address:Port
LISTEN     0      128                                *:22                                   *:*
LISTEN     0      10                                 *:11111                                *:*

11112番ポート以上のリスニングソケットを表示する。
[root@server ~]# ss -lnt4 'sport >= :11112'
State      Recv-Q Send-Q                 Local Address:Port                      Peer Address:Port
LISTEN     0      10                                 *:11112                                *:*
LISTEN     0      10                                 *:11113                                *:*

6.2 IPアドレスによる絞り込み

---------------------------------------------------
1. 事前準備(コネクション確立済ソケットを1つ作成する)
---------------------------------------------------
[root@server ~]# nc -l 11111&
[1] 4585
[root@server ~]# jobs
[1]+  実行中               nc -l 11111 &

ncコマンドを実行して、サーバにTCPコネクションを確認する。
[root@client ~]# nc server 11111

-----------------
2. 初期状態の確認
-----------------
テスト用に作成したソケットが存在することがわかる(★印)
[root@server ~]# ss -nt4
State      Recv-Q Send-Q              Local Address:Port                             Peer Address:Port
ESTAB★    0      0                    192.168.0.10:11111                            192.168.0.20:55064
ESTAB      0      96                   192.168.0.10:22                                192.168.0.6:50875

---------
3. 確認
---------
宛先IPアドレスが"192.168.0.20"のソケットだけを表示する。
[root@server ~]# ss -nt4 dst 192.168.0.20
State      Recv-Q Send-Q              Local Address:Port                             Peer Address:Port
ESTAB      0      0                    192.168.0.10:11111                            192.168.0.20:55064

送信元IPアドレスが"192.168.0.10"のソケットだけを表示する。
[root@server ~]# ss -nt4 src 192.168.0.10
State      Recv-Q Send-Q              Local Address:Port                             Peer Address:Port
ESTAB      0      0                    192.168.0.10:11111                            192.168.0.20:55064
ESTAB      0      96                   192.168.0.10:22                                192.168.0.6:50875

送信元IPが"192.168.0.10"、送信元ポート番号は22のソケットだけを表示する。
[root@server ~]# ss -nt4 'src 192.168.0.10 sport == 22'
State      Recv-Q Send-Q              Local Address:Port                             Peer Address:Port
ESTAB      0      96                   192.168.0.10:22          

7 STATE-FILTERで絞り込む方法

ソケットの状態によって、表示するソケットを絞り込むことができます。書式は以下のとおりです。
なお、TCPの各種状態の作り方は、ここ(TCPの各種状態の作り方)を参照してください。

書式
# ss state [STATE-FILTER]
STATE-FILTER
- established
- syn-sent
- syn-recv
- fin-wait-1
- fin-wait-2
- time-wait
- closed
- close-wait
- last-ack
- closing

7.1 TIME-WAIT状態のソケットの調べ方(state time-wait)

サーバでncコマンドを実行する。11111番ポートでリッスンする。
[root@server ~]# nc -l 11111

クライアントでncコマンドを実行する。Ctrl+cを押下してTCPコネクションを切断する。
[root@client ~]# nc master 11111
^C

TIME-WAIT状態のソケットを確認する。
TIME-WAIT状態はデフォルトで60秒間続きます。コネクション切断直後なので、残り時間が59秒になっている(★印)。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q             Local Address:Port            Peer Address:Port
0      0                  192.168.0.20:53691            192.168.0.10:11111         timer:(timewait,★59sec,0)

-中略-

TIME-WAIT状態の残り時間が515ミリ秒であることがわかる(★印)。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q             Local Address:Port            Peer Address:Port
0      0                  192.168.0.20:53691            192.168.0.10:11111         timer:(timewait,★515ms,0)

60秒経過したので、TIME-WAIT状態のソケットが消えた。
[root@client ~]# ss -not state time-wait
Recv-Q Send-Q             Local Address:Port            Peer Address:Port


---------------- (TIME-WAIT状態の補足説明:ここから) -----------------------------
TIME-WAITはアクティブクローズ側で発生する状態です。
clientでCtrl+cを押下してTCPコネクションを切断しているので、
clientからserverにFINパケットが送信されます。
したがって、clientがアクティブクローズ側、serverがパッシブクローズ側になります。

TIME-WAIT状態は、デフォルトで60秒間続きます。60秒経過すると、CLOSED状態に状態遷移します。
なお、教科書的には図1の説明がほとんどですが、tcpdumpで終了シーケンスを観察すると、
図2のような場合がほとんどです。図1も図2も正常です。


             client                  server
    (アクティブクローズ側)      (パッシブクローズ側)
              |                       |
     Ctrl + c |                       |
              |--------- FIN -------->|
              |<-------- ACK(*1) -----|
              |                       |
              |<-------- FIN(*2) -----|
       -*-    |--------- ACK -------->|
        |     |                       |
        |     |                       |
   TIME-WAIT  |                       |
      60(s)   |                       |
        |     |                       |
        |     |                       |
       -*-    |                       |

              図1. TCP終了シーケンス(FIN(*1)とACK(*2)が別々のTCPパケットで送信される場合)
            ==========================================================================


             client                  server
    (アクティブクローズ側)      (パッシブクローズ側)
              |                       |
     Ctrl + c |                       |
              |--------- FIN -------->|
              |<--- FIN(*1)+ACK(*2) --|
              |                       |
       -*-    |--------- ACK -------->|
        |     |                       |
        |     |                       |
   TIME-WAIT  |                       |
      60(s)   |                       |
        |     |                       |
        |     |                       |
       -*-    |                       |

              図2. TCP終了シーケンス(FIN(*1)とACK(*2)が同じTCPパケットで送信される場合)
            ========================================================================

---------------- (TIME-WAIT状態の補足説明:ここまで) -----------------------------

7.2 SYS-SENT状態のソケットの調べ方(state syn-sent)

               クライアント                        サーバ
                 (node1)                           (master)
                    |                                 |
                    |                                 | <- iptables -A INPUT -p tcp --dport 11111 -j DROP
                    |                                 |
                    |                                 | <- nc -l 11111
                    |                                 |
 nc master 11111 -> |                                 |
             -*-    |------------- SYN -------------->| <- 廃棄
              |     |                                 |
           SYS-SENT |------------- SYN -------------->| <- 廃棄
              |     |                                 |
             -*-    |------------- SYN -------------->| <- 廃棄
                    |                                 |


--------------------------
1. サーバ(master)側の設定
--------------------------
クライアント(node1)から到着する11111番ポート宛てのパケットを廃棄する。
[root@master ~]# iptables -A INPUT -p tcp --dport 11111 -j DROP

設定を確認する。
[root@master ~]# iptables -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 13 packets, 1400 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
[root@master ~]#

ncコマンドを実行する。11111番ポートでTCPコネクション確立を待つ。
[root@master ~]# nc -l 11111

-----------------------------
2. クライアント(node1)の設定
-----------------------------
サーバの11111番ポートにTCPコネクションを確立する。
[root@node1 ~]# nc master 11111
Ncat: Connection timed out.


別ターミナルを開いて、ソケットの状態を確認する。SYS-SENT状態のソケットが確認できる。
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,1.569ms,1)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,198ms,1)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,2.636ms,2)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,1.364ms,2)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,163ms,2)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,6.894ms,3)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
0      1                                   192.168.0.20:53698        192.168.0.10:11111        timer:(on,5.783ms,3)
[root@node1 ~]# ss -not state syn-sent
Recv-Q Send-Q                             Local Address:Port         Peer Address:Port
[root@node1 ~]#

-------------
3. あと始末
-------------
[root@master ~]# iptables -D INPUT 1
[root@master ~]# iptables -nvL INPUT --line-numbers
Chain INPUT (policy ACCEPT 5 packets, 488 bytes)
num   pkts bytes target     prot opt in     out     source               destination
[root@master ~]#

7.3 fin-wait-2状態のソケットの調べ方(state fin-wait-2)

8 Namespace(-N)

ネームスペースのソケットの状態を確認する方法を説明します。
ネームスペースの作成、削除等については、ここ(ip netnsコマンドの使い方(ネットワークの実験の幅が広がるなぁ~))を参照ください。

"host1"という名前のネームスペースを作成します。

ターミナル1(ネームスペースの作成)
[root@server ~]# ip netns add host1
[root@server ~]# ip netns list
host1

作成したネームスペースでncコマンドを実行します。
このとき、TCPの11111番ポートでListenします。
ncコマンドの使い方は、ここ(ncコマンドの使い方)を参照ください。

ターミナル1(ポート番号11111でListenする)
[root@server ~]# ip netns exec host1 bash
[root@server ~]# nc -kl 11111
ターミナル2(ソケットの確認)
[root@server ~]# ss -N host1 -l4n
Netid State      Recv-Q Send-Q             Local Address:Port                            Peer Address:Port
tcp   LISTEN     0      10                             *:11111                                      *:*

あと始末をします。作成したネームスペースを削除します。

ターミナル1(ネームスペースの削除)
Ctl + cを押下して、ncコマンドを終了します。
[root@server ~]# nc -kl 11111
^C

ネームスペース(host1)から抜けます。
[root@server ~]# exit
exit

作成したネームスペースを削除します。
[root@server ~]# ip netns del host1
[root@server ~]# ip netns list
[root@server ~]#

9 Recv-Q/Send-Qは何を意味するのか?

結論を先に言うと、Recv-Q/Send-Qはカーネルの送受信バッファに残っている送受信データのバイト数を表します。

9.1 Recv-Qの確認方法

アプリケーションプロセスが、なんらかの理由でカーネルバッファからユーザ空間のバッファに
受信データを読み出せなかったとき、カーネルバッファに受信データが残ったままになります。
このとき、ssコマンドを実行すると、カーネルバッファに残った受信データのバイト数が、
Recv-Qに表示されます。ここでは、サーバ側のncプロセスを停止状態にすることで、
カーネル受信バッファからの受信データ読み出しができない状態を作って、そのことを確認します。

サーバ側(192.168.0.100)は1111番ポートでTCPコネクション確立を待つ。
[root@server ~]# nc -kl 11111

クライアン側でサーバの11111番ポートにTCPコネクション確立をする。
[root@client ~]# nc 192.168.0.100 11111

Ctrl +Z を押下して、サーバ側のncプロセスを停止状態にする。
[root@server ~]# nc -kl 11111
^Z
[1]+  停止                  nc -kl 11111

クライアント側で5文字入力する。その後、Enterを押下する。合計6文字入力したことになる。
[root@client ~]# nc 192.168.0.100 11111
12345

サーバ側でssコマンドを実行する。Recv-Qの値が6になっている。
[root@server ~]# ss -nt
State       Recv-Q Send-Q                                 Local Address:Port                                                Peer Address:Port
ESTAB     ★6      0                                      192.168.0.100:11111

停止中のncプロセスを実行する。実行すると、ncプロセスは、カーネルバッファから6バイトのデータを読み出すことになります。
[root@server ~]# fg 1
nc -kl 11111
12345

再度、ssコマンドを実行する。
Recv-Qの値が0になったことがわかる。カーネルの受信バッファに何も残っていないことがわかる。
[root@server ~]# ss -nt
State       Recv-Q Send-Q                                 Local Address:Port                                                Peer Address:Port
ESTAB     ★0      0                                      192.168.0.100:11111

以上より、Recv-Qはカーネル受信バッファに残っているバイト数を表していることがわかる。

9.2 Send-Qの確認方法

カーネルの送信バッファ(Send-Q)に残っているデータは、相手からACKが返ってくると削除されます。
ここでは、クライアントからサーバに送信したデータを、サーバ側で廃棄する設定をして、
サーバからクライアントにACKが返らないような状況を作ります。その結果、クライアント側の
送信バッファ(Send-Q)に送信データが残ったままの状態を確認します。

サーバでncコマンドを実行する。11111番ポートでTCPコネクション確立を待つ。
[root@server ~]# nc -kl 11111

クライアントからサーバにTCPコネクションを確立する。
[root@client ~]# nc server 11111

TCPコネクションを確認する。コネクションが確立できたことがわかる、
[root@client ~]# ss -nt 'dport == :11111'
State       Recv-Q Send-Q        Local Address:Port                       Peer Address:Port
ESTAB       0      0             192.168.0.110:51494                     192.168.0.100:1111

サーバ側で宛先TCPポート番号11111番のパケットを廃棄する設定をする。
[root@server ~]# iptables -A INPUT -p tcp --dport 11111 -j DROP

サーバに6バイトのデータを送信する。
[root@client ~]# nc server 11111
12345

コネクションの状態を確認する。カーネルの送信バッファに送信データが6バイト(★)保留されていることがわかる。
[root@client ~]# ss -nt 'dport == :11111'
State       Recv-Q Send-Q        Local Address:Port                       Peer Address:Port
ESTAB       0    ★6             192.168.0.110:51494                     192.168.0.100:11111

さらに、サーバに6バイト送信する。
[root@client ~]# nc server 11111
12345
12345

コネクションの状態を確認する。カーネルの送信バッファに送信データが12バイト(★)保留されていることがわかる。
[root@client ~]# ss -nt 'dport == :11111'
State       Recv-Q Send-Q        Local Address:Port                       Peer Address:Port
ESTAB       0    ★12            192.168.0.110:51494                     192.168.0.100:11111

TCPポート番号11111宛てパケット廃棄の設定を削除する。
[root@server ~]# iptables -F
[root@server ~]#

コネクションの状態を確認する。
保留されていたパケットがサーバに送信されたので、送信バッファの送信データが0(★)になったことがわかる。
[root@client ~]# ss -nt 'dport == :11111'
State       Recv-Q Send-Q        Local Address:Port                       Peer Address:Port
ESTAB       0    ★0             192.168.0.110:51494                     192.168.0.100:11111

10 mオプション

カーネルの送受信バッファサイズや送受信バッファにたまっている
パケットサイズ(管理領域込み)等を表示することができます。

10.1 実行例

[root@client ~]# ss -mt4
State      Recv-Q Send-Q           Local Address:Port        Peer Address:Port
ESTAB      0      96                192.168.0.20:ssh          192.168.0.6:51290
         skmem:(r0,rb474628,t0,tb139264,f1792,w2304,o0,bl0)

10.2 意味

項目 カーネルの該当部分 意味
r sk_rmem_alloc_get(sk) 受信バッファ(sk_receive_queue)に存在するパケットのサイズ(sk_buff構造体の管理領域も含む)を表す。
rb sk->sk_rcvbuf 受信バッファのサイズを表す。上記結果は474,628(byte)であることを表している。net.ipv4.tcp_rmem[2]まで増加可能。
t sk_wmem_alloc_get(sk) 送信バッファ(sk_write_queue)に存在するパケットのサイズ(sk_buff構造体の管理領域も含む)を表す。
tb sk->sk_sndbuf 送信バッファのサイズを表す。上記結果は139,264(byte)であることを表している。net.ipv4.tcp_wmem[2]まで増加可能。
f sk->sk_forward_alloc
w sk->sk_wmem_queued
o atomic_read(&sk->sk_omem_alloc)
bl sk->sk_backlog.len

10.3 項目rの確認結果

サーバを起動する。サーバは、11111番ポートでListenする。
[root@server ~]# nc -l 11111

サーバの11111番ポートにTCPコネクションを確立する。
[root@client ~]# nc server 11111

ncプロセスのソケットの状態を確認する。Recv-Qやrの値は0であることがわかる。
[root@server ~]# ss -antm4 'sport == :11111'
State       Recv-Q Send-Q                     Local Address:Port      Peer Address:Port
ESTAB       0      0                           192.168.0.10:11111    192.168.0.110:47124
         skmem:(r0,rb369280,t0,tb87040,f0,w0,o0,bl0)

Ctrl + zを押下して、サーバを停止状態にする。
[root@server ~]# nc -l 11111
^Z
[1]+  停止                  nc -l 11111

クライアントからサーバに6バイト送信する(改行コード含む)。
[root@client ~]# nc server 11111
12345

ncプロセスのソケットの状態を確認する。
カーネル受信バッファに存在するパケットのサイズ(Recv-Q)が6バイト(★)になったことがわかる。
また、管理領域を含めたサイズ(r)が768バイト(●)になったことがわかる。
[root@server ~]# ss -antm4 'sport == :11111'
State       Recv-Q Send-Q                     Local Address:Port        Peer Address:Port
ESTAB     ★6      0                           192.168.0.10:11111      192.168.0.110:47124
         skmem:(●r768,rb369280,t0,tb87040,f3328,w0,o0,bl0)

後始末(サーバの起動)をする。
[root@server ~]# fg
nc -l 11111

11 iオプション

iオプションを使うと、ソケットの詳細情報を表示できます。

11.1 実行例

リスニングソケットの場合
[root@client ~]# ss -ilt4
State      Recv-Q Send-Q           Local Address:Port                 Peer Address:Port
LISTEN     0      128                          *:ssh                             *:*
         cubic rto:1000 mss:536 cwnd:10 segs_in:18 lastsnd:7672235 lastrcv:7672235 lastack:7672235
コネクション確立済ソケットの場合
[root@client ~]# ss -it4
State      Recv-Q Send-Q              Local Address:Port                 Peer Address:Port
ESTAB      0      96                   192.168.0.20:ssh                   192.168.0.6:51290
         cubic wscale:2,7 rto:388 rtt:187.876/24.53 ato:40 mss:1460 cwnd:6 ssthresh:5 bytes_acked:1096855 bytes_received:151218 segs_out:3257 segs_in:3530 send 373.0Kbps lastsnd:2 lastrcv:66 lastack:66 pacing_rate 746.0Kbps unacked:1 retrans:0/5 rcv_rtt:377989 rcv_space:47120

12 eオプション

ソケットの詳細情報を表示することができます。
ソケットのinode番号(35984)やアドレス(ffff880133030000)が表示されていることがわかります。
アドレスとは、sk構造体の先頭アドレスを意味しています。

[root@server ~]# ss -et4
State      Recv-Q Send-Q                               Local Address:Port                                                Peer Address:Port
ESTAB      0      36                                    192.168.3.20:ssh                                                  192.168.3.3:59507                 timer:(on,235ms,0) ino:35984 sk:ffff880133030000 <->

13 調査用メモ(自分用)

mオプションについて調べる。mオプションはソケットのメモリ使用量
なお、下記で使用しているSystemtapの詳細は、以下を参照してください。
SystemTapの使い方
SystemTapの使い方(User-Space Probing)

13.1 おおまかな流れを把握する(ssコマンド側)

mオプションをつけて、ssコマンドを実行したときの関数呼び出しの流れを確認する。

スクリプトを作成する。
[root@server stap]# vi ss.stp
[root@server stap]# cat ss.stp
probe process("/usr/sbin/ss").function("*").call
{
  printf("pp=%s\n", pp())
}

ssコマンドを実行する。mオプションを付けて、ソケットのメモリ使用量を確認する。
[root@server stap]# ss -lt4m 'sport == :22'
State       Recv-Q Send-Q                               Local Address:Port                                                Peer Address:Port
LISTEN      0      128                                              *:ssh                                                            *:*
         skmem:(r0,rb87380,t0,tb16384,f0,w0,o0,bl0)

ssコマンド実行時のstapの実行結果は下記のとおり。
[root@server stap]# stap -v ss.stp
-中略-
pp=process("/usr/sbin/ss").function("_start").call
pp=process("/usr/sbin/ss").function("__libc_csu_init").call
pp=process("/usr/sbin/ss").function("_init").call
pp=process("/usr/sbin/ss").function("frame_dummy").call
pp=process("/usr/sbin/ss").function("register_tm_clones").call
pp=process("/usr/sbin/ss").function("main@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:3633").call
pp=process("/usr/sbin/ss").function("ssfilter_parse@/usr/src/debug/iproute-3.10.0-74.el7/misc/ssfilter.y:274").call
pp=process("/usr/sbin/ss").function("yyparse@/usr/src/debug/iproute-3.10.0-74.el7/misc/ssfilter.c:1030").call
pp=process("/usr/sbin/ss").function("tcp_show@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2488").call
pp=process("/usr/sbin/ss").function("inet_show_netlink@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2399").call
pp=process("/usr/sbin/ss").function("rtnl_open_byproto@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:46").call
pp=process("/usr/sbin/ss").function("rtnl_dump_filter_nc@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:301").call
pp=process("/usr/sbin/ss").function("rtnl_dump_filter_l@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:194").call
pp=process("/usr/sbin/ss").function("show_one_inet_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2384").call
pp=process("/usr/sbin/ss").function("inet_show_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2178").call
pp=process("/usr/sbin/ss").function("parse_rtattr@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:757").call
pp=process("/usr/sbin/ss").function("parse_rtattr_flags@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:762").call
pp=process("/usr/sbin/ss").function("inet_stats_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1629").call
pp=process("/usr/sbin/ss").function("sock_state_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:838").call
pp=process("/usr/sbin/ss").function("is_sctp_assoc@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:829").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("generic_proc_open@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:314").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("tcp_show_info@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2006").call
pp=process("/usr/sbin/ss").function("print_skmeminfo@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1965").call
pp=process("/usr/sbin/ss").function("show_one_inet_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2384").call
pp=process("/usr/sbin/ss").function("inet_show_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2178").call
pp=process("/usr/sbin/ss").function("parse_rtattr@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:757").call
pp=process("/usr/sbin/ss").function("parse_rtattr_flags@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:762").call
pp=process("/usr/sbin/ss").function("inet_stats_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1629").call
pp=process("/usr/sbin/ss").function("sock_state_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:838").call
pp=process("/usr/sbin/ss").function("is_sctp_assoc@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:829").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("tcp_show_info@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2006").call
pp=process("/usr/sbin/ss").function("print_skmeminfo@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1965").call
pp=process("/usr/sbin/ss").function("show_one_inet_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2384").call
pp=process("/usr/sbin/ss").function("inet_show_sock@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2178").call
pp=process("/usr/sbin/ss").function("parse_rtattr@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:757").call
pp=process("/usr/sbin/ss").function("parse_rtattr_flags@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:762").call
pp=process("/usr/sbin/ss").function("inet_stats_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1629").call
pp=process("/usr/sbin/ss").function("sock_state_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:838").call
pp=process("/usr/sbin/ss").function("is_sctp_assoc@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:829").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("inet_addr_print@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1065").call
pp=process("/usr/sbin/ss").function("format_host@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:826").call
pp=process("/usr/sbin/ss").function("format_host_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:790").call
pp=process("/usr/sbin/ss").function("rt_addr_n2a_r@/usr/src/debug/iproute-3.10.0-74.el7/lib/utils.c:674").call
pp=process("/usr/sbin/ss").function("sock_addr_print_width@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:863").call
pp=process("/usr/sbin/ss").function("tcp_show_info@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:2006").call
pp=process("/usr/sbin/ss").function("print_skmeminfo@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1965").call
pp=process("/usr/sbin/ss").function("rtnl_dump_filter_nc@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:301").call
pp=process("/usr/sbin/ss").function("rtnl_dump_filter_l@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:194").call
pp=process("/usr/sbin/ss").function("rtnl_close@/usr/src/debug/iproute-3.10.0-74.el7/lib/libnetlink.c:38").call
pp=process("/usr/sbin/ss").function("__do_global_dtors_aux").call
pp=process("/usr/sbin/ss").function("deregister_tm_clones").call
pp=process("/usr/sbin/ss").function("_fini").call

上記stapの実行結果より、ソースコードを確認する。
print_skmeminfo()の1988,1999行目(★)でソケットのメモリ使用量を表示していることがわかる。
1965 static void print_skmeminfo(struct rtattr *tb[], int attrtype)
1966 {
1967         const __u32 *skmeminfo;
1968 
1969         if (!tb[attrtype]) {
1970                 if (attrtype == INET_DIAG_SKMEMINFO) {
1971                         if (!tb[INET_DIAG_MEMINFO])
1972                                 return;
1973 
1974                         const struct inet_diag_meminfo *minfo =
1975                                 RTA_DATA(tb[INET_DIAG_MEMINFO]);
1976 
1977                         printf(" mem:(r%u,w%u,f%u,t%u)",
1978                                         minfo->idiag_rmem,
1979                                         minfo->idiag_wmem,
1980                                         minfo->idiag_fmem,
1981                                         minfo->idiag_tmem);
1982                 }
1983                 return;
1984         }
1985 
1986         skmeminfo = RTA_DATA(tb[attrtype]);
1987 
1988      ★ printf(" skmem:(r%u,rb%u,t%u,tb%u,f%u,w%u,o%u",
1989                skmeminfo[SK_MEMINFO_RMEM_ALLOC],
1990                skmeminfo[SK_MEMINFO_RCVBUF],
1991                skmeminfo[SK_MEMINFO_WMEM_ALLOC],
1992                skmeminfo[SK_MEMINFO_SNDBUF],
1993                skmeminfo[SK_MEMINFO_FWD_ALLOC],
1994                skmeminfo[SK_MEMINFO_WMEM_QUEUED],
1995                skmeminfo[SK_MEMINFO_OPTMEM]);
1996 
1997         if (RTA_PAYLOAD(tb[attrtype]) >=
1998                 (SK_MEMINFO_BACKLOG + 1) * sizeof(__u32))
1999               ★ printf(",bl%u", skmeminfo[SK_MEMINFO_BACKLOG]);
2000 
2001         printf(")");
2002 }
2003 

13.2 おおまかな流れを把握する(カーネル側)

スクリプトを作成する。
[root@server stap]# vi ss.stp
[root@server stap]# cat ss.stp
#!/usr/bin/stap

probe process("/usr/sbin/ss").function("print_skmeminfo@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c")
{
  printf("pp=%s\n", pp())
}

probe kernel.function("sock_diag_put_meminfo@net/core/sock_diag.c")
{
  printf("pp=%s\n", pp())
}

スクリプトを実行する。
[root@server stap]# stap -v ss.stp

ssコマンドを実行する。このとき、ソケットのメモリ量を表示する。
[root@server stap]# ss -lt4m 'sport == :22'
State       Recv-Q Send-Q                               Local Address:Port                                                Peer Address:Port
LISTEN      0      128                                              *:ssh                                                            *:*
         skmem:(r0,rb87380,t0,tb16384,f0,w0,o0,bl0)

スクリプトを実行する。
[root@server stap]# stap -v ss.stp
-中略-
pp=kernel.function("sock_diag_put_meminfo@net/core/sock_diag.c:35")
pp=process("/usr/sbin/ss").function("print_skmeminfo@/usr/src/debug/iproute-3.10.0-74.el7/misc/ss.c:1965")
pp=kernel.function("sock_diag_put_meminfo@net/core/sock_diag.c:35")

sock_diag_put_meminfo()関数で、ソケットが使用しているメモリ量を取得しているようです。
また、カーネルとssコマンドで同じマクロ名を使用しているようです。
net/core/sock_diag.c
  35 int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
  36 {
  37         u32 mem[SK_MEMINFO_VARS];
  38 
  39         mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk);
  40         mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
  41         mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk);
  42         mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
  43         mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
  44         mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
  45         mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
  46         mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
  47         mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops);
  48 
  49         return nla_put(skb, attrtype, sizeof(mem), &mem);
  50 }

x 参考情報

10 examples of Linux ss command to monitor network connections

ss command in Linux
10 examples of Linux ss command to monitor network connections
15+ “ss” Command Usage Examples in Linux

hana_shin
写真は淡路島SAから明石海峡大橋を撮影したものです('19夏撮影)。'20年夏も3年連続で四国、大阪に行く予定!毎回車でいってます。今から楽しみぃ~。次は、四国の四万十川に行ってみたいけど、ちょっと遠いかな?最近はネットワークに力を入れてます。保有国家資格:ネットワークスペシャリスト、オンライン情報処理技術者。メールは hana.shin.2018@gmail.com まで。
https://hana-shin.hatenablog.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした