![Socat が TCP 接続を閉じない](https://rvso.com/image/1490203/Socat%20%E3%81%8C%20TCP%20%E6%8E%A5%E7%B6%9A%E3%82%92%E9%96%89%E3%81%98%E3%81%AA%E3%81%84.png)
socat 1.7.3.1-r0
Linux サーバーで次のコマンドを使用して実行しますalpine 3.3
。
socat -d -d -d PTY,link=/dev/ttyFOOBAR,echo=0,raw,unlink-close=0 TCP-LISTEN:7000,forever,reuseaddr
Socat
クライアントをリッスンし、仮想シリアル ポートから/dev/ttyFOOBAR
クライアントにデータを渡し、TCP 経由で戻すことで双方向通信を作成します。クライアントが切断されると、socat
終了する必要があります。
このような接続が確立されると、socat は以下をログに記録します。
I socat by Gerhard Rieger - see www.dest-unreach.org I This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/) I This product includes software written by Tim Hudson ([email protected]) I setting option "symbolic-link" to "/dev/ttyFOOBAR" I setting option "echo" to 0 I setting option "raw" I setting option "unlink-close" to 0 I openpty({5}, {6}, {"/dev/pts/3"},,) -> 0 N PTY is /dev/pts/3 I setting option "forever" to 1 I setting option "so-reuseaddr" to 1 I socket(2, 1, 6) -> 7 I starting accept loop N listening on AF=2 0.0.0.0:7000 I accept(7, {2, AF=2 CLIENT_IP:PORT}, 16) -> 8 N accepting connection from AF=2 CLIENT_IP:PORT on AF=2 172.20.0.2:7000 I permitting connection from AF=2 CLIENT_IP:PORT I close(7) I resolved and opened all sock addresses N starting data transfer loop with FDs [5,5] and [8,8]
ss
サーバー上のコマンドは以下を出力します:
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp ESTAB 0 0 172.20.0.2:7000 CLIENT_IP:PORT
問題は、クライアントを切断すると (電源をオフにすると)、TCP 接続がまだ確立されていて、socat から追加のログが送信されないことです。ss
接続は ESTAB として表示されます。なぜかわかりますか? クライアントに再度接続すると、ログに次の内容が表示されます。
W read(8, 0x7fa8f48c4020, 8192): Connection reset by peer
N socket 2 to socket 1 is in error
N socket 2 (fd 8) is at EOF
I poll timed out (no data within 0.500000 seconds)
I close(5)
I shutdown(8, 2)
I shutdown(8, 2): Socket not connected
N exiting with status 0
しかし、なぜ切断時ではなく接続時にこれが起こるのでしょうか?
答え1
クライアントをシャットダウンすると、相手側に自分がいなくなったことを伝える機会がなくなります。ピアがなくなったことを知る唯一の方法は、そのピアに何かを送信してみて、応答がないことに気づくことです。
アプリケーションでデッド ピアの検出が必須である場合は、デッド ピア検出を実装する必要があります。keepalive
のオプションを有効にすることでこれを実現できますsocat
が、デッド ピアの検出には数時間かかることがあります。定期的に何かを送信することでもこれを実現できます。ピアがデッドになると送信がタイムアウトし、検出がトリガーされます。相手側がデータを送信するはずの場合、期待するデータを受信していなければ中止できます (おそらくsocat
の-T
フラグを使用)。