파이썬의 소켓 recv 메서드에서 시간 제한을 설정하는 방법은 무엇입니까?


110

파이썬의 소켓 recv 메서드에 시간 제한을 설정해야합니다. 어떻게하나요?


2
참고로 타임 아웃을 사용하기로 선택했다면 ... 타임 아웃을 처리하는 방법을 알아야합니다. 이 SO 질문은 시간 초과가 발생했을 때 처리에 대해 이야기합니다. stackoverflow.com/questions/16745409
Trevor Boyd Smith

답변:


125

일반적인 방법은 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()것이지만 다른 답변에서 해당 솔루션을 명시 적으로 거부 한 것을 확인했습니다.


16
사용 select은 좋지만 "할 수 없습니다"라고 말하는 부분은 오해의 소지가 socket.settimeout()있습니다.
nosklo

1
지금은 더 낫지 만 대답이 "명시 적으로 거부 된"부분은 알 수 없습니다.
nosklo

7
사용에 대한 한 가지주의 사항 select은 Windows 시스템에서 실행중인 경우 일부 데이터가 도착 select하자마자 반환하는 습관이 있지만 반드시 전부 는 아니므 로 WinSock 라이브러리에 의존 합니다. 따라서 모든 데이터가 수신 될 때까지 계속 호출하려면 루프를 통합해야합니다 . 모든 데이터를 얻었는지 아는 방법은 (불행히도) 당신에게 달려 있습니다. 종결 자 문자열, 특정 바이트 수를 찾거나 정의 된 시간 초과를 기다리는 것을 의미 할 수 있습니다. select.select()
JDM 2013 년

4
소켓을 비 차단으로 설정해야하는 이유는 무엇입니까? 나는 그것이 선택 호출에 중요하다고 생각하지 않으며 (이 경우 설명자를 읽을 수 있거나 시간 초과가 만료 될 때까지 차단됨) 선택이 충족되면 recv ()가 차단되지 않습니다. recvfrom ()을 사용하여 시도했는데 setblocking (0)없이 올바르게 작동하는 것 같습니다.
HankB 2015

1
겠습니까 ready[0]서버의 응답에는 몸이 존재하지 않는 경우에만 거짓?
matanster

60

16
recv가 시간 초과되지 않습니다 (적어도 시도했을 때). accept () 만 시간 초과되었습니다.
Oren S

9
socket.recv ()는 정확히 의도 한대로 socket.settimeout ()을 설정 한 후 제대로 시간 초과되는 것 같습니다. 내가 이것을 만들고 있는가? 다른 사람이 이것을 확인할 수 있습니까?
Aeonaut

3
@Aeonaut 나는 이것이 대부분의 시간 동안 recv () 시간을 초과한다고 생각하지만 경쟁 조건이 있습니다. socket.recv ()에서 Python (2.6)은 내부적으로 시간 제한과 함께 select / poll을 호출 한 다음 recv ()가 바로 호출됩니다. 따라서 차단 소켓을 사용하고이 두 호출 사이에서 다른 끝점 충돌이 발생하면 recv ()에 무기한 중단 될 수 있습니다. 비 차단 소켓을 사용하는 경우 파이썬은 내부적으로 select.select를 호출하지 않으므로 Daniel Stutzbach의 대답이 올바른 방법이라고 생각합니다.
emil.p.stanchev

4
실제로 select ()가 반환 될 때 오해했을 것이므로 이전 주석을 긁어주십시오. Beej 's Guide는 위의 내용이 recv에 시간 제한을 구현하는 유효한 방법이라고 말합니다. beej.us/guide/bgnet/output/html/singlepage/… 그래서 신뢰할 수있는 출처입니다.
emil.p.stanchev

2
select이 솔루션이 하나의 라이너 (유지하기 쉽고 잘못 구현할 위험이 적음)이고 후드 아래에서 선택을 사용할 때 사용하는 솔루션 이 선호되는 이유를 모르겠습니다 (구현은 @DanielStuzbach 답변과 동일합니다).
트레버 보이드 스미스

33

으로 모두 언급 select.select()하고 socket.settimeout()작동합니다.

필요에 따라 settimeout두 번 전화해야 할 수도 있습니다 . 예 :

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)

3
나는 당신이이 기능을 어떻게 찌르고 찌르 든 상관없이 그가 내가있는 곳에서 똑같은 일을하고 있다고 생각한다. 지금 2 ~ 4 번의 타임 아웃을 시도했는데 여전히 멈 춥니 다. settimeout도 중단됩니다.
Casey Daniel

1
당신이 전화로 .settimeout()한 번 이상 당신이 부를 수있는 setdefaulttimeout()첫번째 장소에있는 방법을.
mvarge 2011

12

응답을 받기 전에 시간 제한을 설정하고 응답을받은 후 다시 없음으로 설정할 수 있습니다.

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)

5

찾고있는 시간 초과는 서버 측을 구현하는 경우 기본 소켓이 아닌 연결 소켓의 시간 초과입니다. 즉, socket.accept()method 의 출력 인 연결 소켓 개체에 대한 또 다른 제한 시간이 있습니다. 따라서:

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)

2

이전 회신에서 언급했듯이 다음과 같이 사용할 수 있습니다. .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()

이게 도움이 되길 바란다!!


2

socket.settimeout()초 수를 나타내는 정수 인수를 허용하는 것을 사용할 수 있습니다 . 예를 들어 socket.settimeout(1)시간 제한을 1 초로 설정합니다.


2

이것은 기본 C를 사용합니다.

timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)

이 전송 및 사용 RECV 시간 제한에 대해 서로 다른 값을 설정하는 일을 허용하기 때문에 이것은 대단한 SO_RCVTIMEOSO_SNDTIMEO.
jtpereyda

2그리고 왜 100? 시간 초과 값은 무엇입니까? 어떤 단위로?
Alfe

timeval = struct.pack('ll', sec, usec) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)usec = 10000은 10ms를 의미합니다.
Tavy

1
#! /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

0

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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.