Pythonのsocket.recv()は、ノンブロッキングソケットの場合、タイムアウトが発生するまでデータを受信しなかった場合、何を返すのでしょうか?
質問
基本的に、私はいくつかの場所で次のように読みました。
socket.recv()
は読み取れるものなら何でも返すか、相手側がシャットダウンしたことを示す空の文字列を返すということです (公式ドキュメントでは、接続がシャットダウンしたときに何を返すかについて触れていません...素晴らしい!)。これはブロッキングソケットの場合、すべてうまくいき、ダンディです。
recv()
は実際に受信するものがあるときだけ返すと知っているので、 空文字列を返したとき、それは
を返さなければなりません。
は相手側が接続を閉じたことを意味しますよね?
わかりました、しかし、私のソケットがノンブロッキングである場合はどうなるのでしょうか?私は少し探しましたが(十分ではないかもしれませんが、誰が知っていますか)、ノンブロッキングソケットを使用して相手側が接続を閉じたときにそれを伝える方法を見つけることができません。これを教えてくれるメソッドや属性はないようです。
recv()
の戻り値を空文字列と比較することは、まったく役に立たないように思われます。
簡単な例として、ソケットのタイムアウトが 1.2342342 (負でない数字なら何でも) 秒に設定されていると仮定して、私が
socket.recv(1024)
を呼び出したが、相手側はその 1.2342342 秒の間に何も送信してこなかったとします。このとき
recv()
の呼び出しは空の文字列を返すので、接続がまだ続いているのかどうかの手がかりがありません...。
どのように解決するのですか?
利用可能なデータがないノンブロッキングソケットの場合、recv は socket.error 例外をスローし、例外の値は EAGAIN または EWOULDBLOCK の errno を持ちます。例
import sys
import socket
import fcntl, os
import errno
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)
while True:
try:
msg = s.recv(4096)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
else:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)
でタイムアウトによるノンブロッキング動作を有効にした場合、状況は少し異なります。
socket.settimeout(n)
または
socket.setblocking(False)
. この場合にも socket.error が発生しますが、タイムアウトの場合は例外に付随する値が常に 'timed out' に設定された文字列となります。そこで、このケースを処理するために、次のようにします。
import sys
import socket
from time import sleep
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.settimeout(2)
while True:
try:
msg = s.recv(4096)
except socket.timeout, e:
err = e.args[0]
# this next if/else is a bit redundant, but illustrates how the
# timeout exception is setup
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
# Something else happened, handle error, exit, etc.
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
# got a message do something :)
コメントにあるように、これはソケットをノンブロッキングモードにするためにOS固有の機能に依存しないので、より移植性の高いソリューションでもあります。
参照 recv(2) と python ソケット をご覧ください。
関連
-
[解決済み] 億の相対的輸入
-
[解決済み] Flaskで1時間ごとに関数を実行するようにスケジュールするには?
-
[解決済み] Spyderを仮想環境で動作させるには?
-
[解決済み] Pandasの'Freq'タグにはどのような値が有効ですか?
-
[解決済み] スペースがないテキストを単語のリストに分割する方法
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?
-
[解決済み] Pythonの文字列の前にあるbという接頭辞は何を意味するのですか?
-
[解決済み] virtualenvsはどこに作成するのですか?
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] pipの依存性/必要条件をリストアップする方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Flaskで1時間ごとに関数を実行するようにスケジュールするには?
-
[解決済み] なぜ(0-6)は-6=偽なのか?重複
-
[解決済み] Django Rest Framework ファイルアップロード
-
[解決済み] PythonからSMTPを使用してメールを送信する
-
[解決済み] ファブリック経由でデプロイユーザとしてvirtualenvを有効化する
-
[解決済み] 古いバージョンのPythonにおける辞書のキーの並び順
-
[解決済み] Django で全てのリクエストヘッダを取得するにはどうすれば良いですか?
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] Pandasのデータフレーム内の文字列を'date'データ型に変換するにはどうしたらいいですか?
-
[解決済み] あるメソッドが複数の引数のうち1つの引数で呼び出されたことを保証する