TwistedのabortConnection

TwistedでTCPサーバを書いていて、loseConnectionだと実は切断できないケースがたぶんあるような気がする、と思ってドキュメントをよんでいてabortConnectionを発見した。

abortConnectionとloseConnectionの違いは、 Writing Servers に説明があって、

In the code above, loseConnection is called immediately after writing to the transport. The loseConnection call will close the connection only when all the data has been written by Twisted out to the operating system, so it is safe to use in this case without worrying about transport writes being lost. If a producer is being used with the transport, loseConnection will only close the connection once the producer is unregistered.
In some cases, waiting until all the data is written out is not what we want. Due to network failures, or bugs or maliciousness in the other side of the connection, data written to the transport may not be deliverable, and so even though loseConnection was called the connection will not be lost. In these cases, abortConnection can be used: it closes the connection immediately, regardless of buffered data that is still unwritten in the transport, or producers that are still registered. Note that abortConnection is only available in Twisted 11.1 and newer.

となっている。たぶん、Due to network failuresのケースに該当してるんだとおもうんだけど、TCP的にPUSHがおくられているのに、ACKが来ないケースが大半で、まあ、要は相手はもういないんだろう、というのがパケットキャプチャした結果で、このときに、loseConnectionだと結局TCPの再送タイマで再送が失敗するまでコネクションが切断されないということになるっぽい?というわけで、こういうケースの場合には、abortConnectionを呼ぶのがよい?ということなんだろうか。

ただ、問題というか、自分の中の謎は2つ残っていて、なんでこういうTCP接続が残ったままのつもりになっているのかというのと、ていうか、loseConnectionを呼ぶべきか、abortConnectionを呼ぶべきかってどうやって判断すればいいの?というあたり。

今回のサーバは、相手は起動していてがんばって働いている間は、ずっとTCPを維持し続けるという仕様で、且つ、最低でも15秒に一回はサーバにデータが送信されるはず、というサーバで、でも実際に運用してみると、どうもTCPは維持されているつもりなのに、かなりの時間データがきていなくて、実際なにかサーバ側からデータを書いてもおそらく届いていなそうという話のはず。 その中で、なんでこういうTCP接続がのこったままなのか、という話は、おそらくは3Gとかの不安定な回線でSYN,ACKまでは着弾するんだけど、それ以降の大きめのPUSHはうまく通らないというケースなのかなぁとおもいつつ、実際のケースを見てると、どうもそれだけでもなさそうということで、そもそもどういう原因や環境でこれが起こるかはまだ全然掴めていない。

loseConnectionなのか、abortConnectionなのか、どちらを呼べばいいの?みたいな話は、実際かなりやっかいだなぁとおもっていて、今回は最低でも15秒に一回はデータが来ているはずというのをベースに、120-150秒間隔で実行するLoopingCallで作ったタスク内で最終受信時間をチェックして、ある程度以上の時間受信していなければ切断という処理にした。この場合はおそらくabortConnectionってことでいいんだろうけど、それ以外にも切断をサーバから野動的に呼ぶケースはあり得て(ユーザからのリモートからの切断要請とか)、その場合にも、同様に最終受信時間チェックで、loseかabortを呼び分けるのがいいんかなぁ。。。よくわからん。

LoopingCall

関係ない話だけど、Twistedつながりで、いままでLoopingCallでtask作るときに、startを呼んだらすぐにtaskの内容が実行されてしまうのが嫌で、reactor.callLater(task.start, args)みたいなことをしてたんだけど、LooingCallにはnowって引数があって、これをFalseにすれば、最初いきなり実行しないようになってた。気づかなくてすごい格好悪いことしてた。