TCP socketではwriteの後すぐにcloseしてはいけない
- tetsu_koba
- 61846
- 10
- 24
- 0
TCPのsocketでwriteの後にすぐcloseしていると、読み込み側が最後までデータを読めないことがある。sockoptのSO_LINGERは効果なし。closeの前に2秒sleepすればうまくいく。こんなんでいいのか??
2012-04-03 14:05:12@tetsu_koba キューの中身を送信前に、キューを破棄してしまうのが原因だと思うので、ioctlでSIOCOUTQを見てキューの送信残が0になるのを待つと良いかと。
2012-04-03 14:08:29TCPsocketのwriteの後にすぐcloseするのでなく、shutdown(sock, SHUT_WR); にして、readで読み込み側がcloseしてEOFになるのを確認してから、書き込み側をcloseするようにした。これでいいのかな??
2012-04-03 14:09:03@yitabashi ありがとう。ぐぐるといろいろ違うことが書いてあるけど鉄板のやりかたは無いってことなのかな。ioctlでSIOCOUTQはLinux固有らしい。今は対象はLinuxだからいいけど。
2012-04-03 14:19:29TCP sokcetでwriteでデータ書き込みしても、相手側にそれが届くまでcloseしてはいけない。shutdown(sock, SHUT_WR)で、これ以上書き込まないことを相手側に通知できる。相手側がcloseしたことはreadで0が返ってくるのでわかる。
2012-04-03 14:36:24@tetsu_koba ノンブロックソケットにsendfile()で書き出すときも、先の方法でキューが空であることを確認してからでないとデータを上書きして壊してしまいます(2.6.18で確認。多分まだ直ってない)。バッファから吐き出した時点で書込完了通知が上がってるのが原因かと。
2012-04-03 14:39:21TCPで最後のデータを受信できないのを回避する方法。 / “The ultimate SO_LINGER page, or: why is my tcp not reliable” http://t.co/kdIlBAye
2012-04-03 14:45:01sockopt SO_LINGER が効果がなかったのが納得できないけど、shutdownでハーフクローズにするのは腑に落ちた。
2012-04-03 14:56:14popen(3)を使って実験したけど、その後にpipe(2), fork(2), dup2(2), execv(2) で書き直した。
2012-04-03 17:53:32もしかして、TCPのsocketをreadでブロックさせておくと相手側が切断したことを監視するのに使えるのか?別に何もデータは来ないけど切断されたらreadがEOFで戻ってくるから、そしたらこっちのプロセスも終了。
2012-04-04 10:41:36@tetsu_koba select()で待ってreadでもいいです。ただ相手が突然死した場合にはFINパケットが来ないのでこっちからなにか投げてやる必要があるかも。KEEPALIVE onにするか自分でpingするか。
2012-04-04 10:45:16TCPで接続したあと、何も通信するデータがない状態で、クライアント側が終了してもサーバ側がそれに気がつかずに、次にwriteするまでずっとプロセスが無駄に残ってしまうという問題があったけど、これで解決できるかも。
2012-04-04 10:45:47@koie 物理的にケーブルが抜けた場合とか、相手側のカーネルが後始末をしない場合はreadのEOFだけだと切れたことに気がつかないということですかね。
2012-04-04 10:49:50@koie 原理的には相手は地球の裏側にあって、途中に無数のノードを経由しているかもしれないですからね。:) 明示的に終了処理されなければ、切断されたのか、時間がかかっているだけなのか判断できないと。
2012-04-04 11:07:41