サーバーに接続しているクライアントのソケットが切断された場合、サーバー側で直ちにそれを感知することはできるのでしょうか?
Pythonの問題じゃあなくてネットワークプログラミングの基本です。
参考までに
http://www.kt.rim.or.jp/~ksk/sock-faq/unix-socket-faq-ja-2.html#...
ひどいプログラムだけどとりあえず確認は出きるはずです。
サンプルの大本はこちらです。
http://www.tutorialspoint.com/python/python_networking.htm
server.py
#!/usr/bin/env python import socket s = socket.socket() host = socket.gethostname() port = 12345 s.bind((host, port)) s.listen(5) while True: c, addr = s.accept() r = c.recv(1024) print r print len(r) r = c.recv(1024) print r print len(r)
client.py
#!/usr/bin/env python import socket s = socket.socket() host = socket.gethostname() port = 12345 s.connect((host, port)) print s.send("abcdefg") s.close
片方のシェルで先にserver.pyを動かします。
$ ./server.py
次に別のシェルでclient.pyを動かします
$ ./client 7
するとサーバー側は次のようになります。
$ ./server.py abcdefg 7 $
シェルが復帰しているので正しくプログラムが終了している事が分かります。
最後の0でクライアント側からcloseを受け取った事が分かります。
疑うならば次のようにクライアント側を修正します。
#!/usr/bin/env python import socket import time s = socket.socket() host = socket.gethostname() port = 12345 s.connect((host, port)) print s.send("abcdefg") while True: time.sleep(1) #s.close
こうするとサーバー側は次の様に動作するはずです。
$ ./client.py 7
シェルが帰らずに s.send("abcdefg") だけを受信していることが分かるはずです。
ネットワークの挙動を本当に正しく知りたければ、難しいかも知れませんがC言語でのプログラミングをお勧めします。
いまや古い本ですがこの本が詳しいです。
Vol:2はIPCなので今回は必要ないです。
UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI
(r, w, e) = select.select([conn], [], [], 0)
if r:
data = conn.recv(1024, socket.MSG_PEEK)
if len(data)==0:
print "Client disconnected."
return False
return True
こんなメソッドで一応接続されてるかどうかはチェックできますよ。
結局、recvで戻り値を確認しているので自分のと本質的には代わりは無いはずです。
recvでの問題点は相手側がcloseしたときだけ分かるということです。
もちろん普通はこれで問題無いはずですが、プログラムが複雑になるとバグで確認出来ないこともあります。
また、通信相手側がcloseしていないからといってバグでrecv/send等を行えない状態になることも考慮に入れる必要があります。
こういう場合は自前でKeepAliveを行います。
つまり定期的に通信を行うことです。
例えば1sec以内に送受信がなければ、1バイトでもよいので通信を行いお互いが送受信をしているので相手側のプログラムは生きている、と判断するわけです。
まぁ本質は同じですが、ノンブロッキングで、MSG_PEEKを使ってキューに残したままにしているので、いつ、何回呼んでも大丈夫にしてます。
> recvでの問題点は相手側がcloseしたときだけ分かるということです。
たしかにこれは問題ですね。相手がネットワークケーブルを抜いたり、OSがハングしていたりした場合は正しく検出できません。
これを直ちに検出する方法は無いですね。
> recvでの問題点は相手側がcloseしたときだけ分かるということです。
これの問題点は、TCPがメッセージ単位通信ではないストリーム通信だと言う点です。
自前KeepAliveのためには、クライアントソケットをハンドルするスレッドとは別のスレッドが定期的に行う必要が出てきますが(複雑な計算やブロッキングなどにより定期的にメッセージ送受信できるとは限らないから)、
プロトコルをうまく定義し、且つ、2つのスレッド間で同期をとったり、メッセージの混入やキューからのKeepAlive用メッセージだけを削除する、など実装はかなり困難です。
特にストリームだとKeepAlive用通信とアプリケーション用通信を分離するのが困難です(UDPのようにメッセージ単位でやりとりできたり、SCTPのように複数のストリームが使えれば問題無いんですが)。
求められる要件にもよりますが、設計/実装の困難さとそれによって救われるケースを天秤にかけると、自前KeepAliveはあまり現実的では無いように思います。
あ、もちろん分かっていますよ。
ただ、今回の質問に対しては本質的に関係ないよということが言いたかっただけです。
>求められる要件にもよりますが、設計/実装の困難さとそれによって救われるケースを天秤にかけると、自前KeepAliveはあまり現実的では無いように思います。
まあ、確かにそこですよね。
自分が以前した仕事の場合は、リアルタイム通信でなおかつcloseが取れないといった場合が多発するので自前KeepAliveが必要でした。
まあ、今回の質問者の場合は必要ないかもですね。
これ以上は本質問からはかけ離れていくのでこれ以上のコメントは控えさせて頂きます。
関係ないけどコメントではてな記法が使えないのは痛いですね。
特にPythonのようなインデントが意味のある言語の場合は。