Насколько я знаю, когда вы вызываете socket.settimeout(value) и устанавливаете значение с плавающей запятой больше 0,0, этот сокет вызовет scocket.timeout, когда вызов, например, socket.recv должен ждать дольше, чем указанное значение.

Но представьте, что мне нужно получить большой объем данных, и я должен вызывать recv() несколько раз, тогда как settimeout влияет на это?

Учитывая следующий код:

to_receive = # an integer representing the bytes we want to receive
socket = # a connected socket

socket.settimeout(20)
received = 0
received_data = b""

while received < to_receive:
    tmp = socket.recv(4096)
    if len(tmp) == 0:
        raise Exception()
    received += len(tmp)
    received_data += tmp

socket.settimeout(None)

Третья строка кода устанавливает время ожидания сокета в 20 секунд. Этот таймаут сбрасывает каждую итерацию? Будет ли превышено время ожидания, только если одна из этих итераций займет более 20 секунд?

А) Как я могу перекодировать его, чтобы оно вызывало исключение, если для получения всех ожидаемых данных требуется более 20 секунд?

Б) Если я не установлю тайм-аут на Нет после того, как мы прочитаем все данные, может ли случиться что-то плохое? (соединение сохраняется, и в будущем может быть запрошено больше данных).

10
Jorky10 19 Дек 2015 в 16:03

3 ответа

Лучший ответ

Тайм-аут применяется к одному вызову операции чтения / записи сокета. Так что следующий звонок снова будет 20 секунд.

A) Чтобы тайм-аут использовался несколькими последовательными вызовами, вам придется отслеживать его вручную. Что-то в этом роде:

deadline = time.time() + 20.0
while not data_received:
    if time.time() >= deadline:
        raise Exception() # ...
    socket.settimeout(deadline - time.time())
    socket.read() # ...

Б) Любой код, который использует сокет с тайм-аутом и не готов обработать исключение socket.timeout, скорее всего завершится ошибкой. Надежнее запомнить значение времени ожидания сокета до начала работы и восстановить его, когда вы закончите:

def my_socket_function(socket, ...):
    # some initialization and stuff
    old_timeout = socket.gettimeout() # Save
    # do your stuff with socket
    socket.settimeout(old_timeout) # Restore
    # etc

Таким образом, ваша функция не повлияет на функционирование кода, который ее вызывает, независимо от того, что они делают с таймаутом сокета.

7
Lav 23 Дек 2015 в 14:19

Смотрите мой серверный скрипт, у вас появится идея использовать его правильно.

import socket
import sys
fragments = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("192.168.1.4",9001))
s.listen(5)
while True:
    c,a = s.accept()
    c.settimeout(10.0)
    print "Someone came in Server from %s and port %s" %(a[0],a[1])
    c.send("Welcome to system")
    while True:
        chunk = c.recv(2048)
        if not chunk.strip():
            break
        else:
            fragments.append(chunk)
            continue
    combiner = "".join(fragments)
    print combiner
    shutdown = str(raw_input("Wanna Quit(Y/y) or (N/n): "))
    if shutdown == 'Y' or shutdown == 'y':
        c.close()
        sys.exit()
    else:
        continue

Этот скрипт просто чтобы дать вам представление о socket.settimeout ().

1
Martijn Pieters 29 Янв 2019 в 11:11

Время ожидания применяется к каждому вызову recv ().

A) просто используйте существующее время ожидания и вызовите recv (to_receive) - т.е. Попытайтесь получить все данные за один вызов recv - на самом деле я не понимаю, почему вы не должны использовать это как способ работы по умолчанию

Б) Ничего плохого не может произойти, но любой другой код, который использует этот сокет, должен знать об обработке тайм-аута.

В существующем коде не должен быть вызов recv () быть recv (max (4096, to_receive-receive)) - таким образом, вы не будете непреднамеренно использовать любые данные, которые следуют после байтов to_receive.

2
barny 19 Дек 2015 в 13:23