回答:
典型的なアプローチは、select()を使用して、データが利用可能になるまで、またはタイムアウトが発生するまで待機することです。recv()
データが実際に利用可能な場合にのみ呼び出します。安全のために、ソケットを非ブロックモードに設定して、recv()
無期限にブロックされないことを保証します。 select()
同時に複数のソケットで待機するためにも使用できます。
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
開いているファイル記述子がたくさんある場合、poll()はのより効率的な代替手段select()
です。
別のオプションは、を使用してソケットのすべての操作にタイムアウトを設定するsocket.settimeout()
ことですが、別の回答でその解決策を明示的に拒否したことがわかります。
select
は良いのですが、「できない」と書いてある箇所が誤解を招きsocket.settimeout()
ます。
select
-Windowsマシンで実行している場合select
、WinSockライブラリを使用してください。WinSockライブラリは、一部のデータが到着するとすぐに戻るという習慣がありますが、必ずしもすべてではありません。したがってselect.select()
、すべてのデータが受信されるまで呼び出しを続けるためにループを組み込む必要があります。すべてのデータを取得したかどうかは、(残念ながら)把握する次第です。つまり、ターミネーター文字列、特定のバイト数を探すか、定義されたタイムアウトを待つだけです。
ready[0]
何のボディは、サーバーの応答がない場合にのみfalseに?
あります socket.settimeout()
select
このソリューションが1つのライナー(保守が容易で、間違った実装のリスクが少ない)であり、内部でselectを使用している(実装は@DanielStuzbachの回答と同じ)場合に、使用するソリューションが推奨される理由がわかりません。
両方select.select()
とsocket.settimeout()
も述べたように動作します。
必要にsettimeout
応じて、2回呼び出す必要がある場合があることに注意してください。
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",0))
sock.listen(1)
# accept can throw socket.timeout
sock.settimeout(5.0)
conn, addr = sock.accept()
# recv can throw socket.timeout
conn.settimeout(5.0)
conn.recv(1024)
.settimeout()
複数回あなたが呼び出すことができますsetdefaulttimeout()
最初の場所での方法を。
サーバー側を実装する場合、探しているタイムアウトは、プライマリソケットのタイムアウトではなく、接続ソケットのタイムアウトです。つまり、接続ソケットオブジェクトには別のタイムアウトがあります。これは、socket.accept()
メソッド。したがって:
sock.listen(1)
connection, client_address = sock.accept()
connection.settimeout(5) # This is the one that affects recv() method.
connection.gettimeout() # This should result 5
sock.gettimeout() # This outputs None when not set previously, if I remember correctly.
クライアント側を実装する場合、それは簡単です。
sock.connect(server_address)
sock.settimeout(3)
以前の返信で述べたように、次のようなものを使用できます.settimeout()
。例:
import socket
s = socket.socket()
s.settimeout(1) # Sets the socket to timeout after 1 second of no activity
host, port = "somehost", 4444
s.connect((host, port))
s.send("Hello World!\r\n")
try:
rec = s.recv(100) # try to receive 100 bytes
except socket.timeout: # fail after 1 second of no activity
print("Didn't receive data! [Timeout]")
finally:
s.close()
これが役に立てば幸いです!!
基礎となるCを使用してこれを試してください。
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
とSO_SNDTIMEO
。
2
そしてなぜ100
?タイムアウト値はどれですか?どのユニットで?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000は10ミリ秒を意味します
#! /usr/bin/python3.6
# -*- coding: utf-8 -*-
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(5)
PORT = 10801
s.bind(('', PORT))
print('Listening for broadcast at ', s.getsockname())
BUFFER_SIZE = 4096
while True:
try:
data, address = s.recvfrom(BUFFER_SIZE)
except socket.timeout:
print("Didn't receive data! [Timeout 5s]")
continue
叫ぶ:https : //boltons.readthedocs.io/en/latest/socketutils.html
バッファ付きソケットを提供します。これにより、次のような非常に便利な機能が数多く提供されます。
.recv_until() #recv until occurrence of bytes
.recv_closed() #recv until close
.peek() #peek at buffer but don't pop values
.settimeout() #configure timeout (including recv timeout)