socket.recv()
, хотя выглядит похожим, не ведет себя так же, как .read()
, если объект похож на файл. «Сырое» программирование сокетов также не выполняет большую часть служебной работы за вас, и ваш код должен справиться с ним.
Потоковый сокет (тип SOCK_STREAM
, который открывается по умолчанию с использованием socket.socket()
- это всего лишь поток байтов и, по сути, агности c контента, который вы проходите через него. Чтобы сделать вещи более сложными, как упомянуто Michael Butscher в комментариях (и здесь сходство с read()
может сбивать с толку), его первый аргумент bufsize
не говорит о том, сколько данных вы получите, он только ограничивает максимальный объем, который вы готовы получить сразу. Я получил буфер такого размера, дайте мне все, что вы можете до этого размера.
Если вы знаете, сколько данных вы хотите получить для любого изображения в вашем случае (и, поскольку они имеют фиксированный размер снимков экрана, я думаю, вам может повезти), вам нужно продолжать повторять вызовы recv()
до тех пор, пока вы не получите полное изображение, затем выполнить свои действия с ним и перейти к следующему.
Это означает, что вы можете заменить:
pack = s.recv(4196540)
на что-то вроде:
item_size = 4196540
pack = b''
while len(pack) < item_size:
remains = item_size - len(pack)
bufsize = 4096 if remains > 4096 else remains
pack += s.recv(bufsize)
Есть и другие способы справиться с этим, но по сути это работает recv
до pack
содержит 4196540
байтов данных (предположительно, одно изображение), а затем вы можете go включить для его обработки.
В противном случае вам придется использовать другой метод: вы можете, например, определить свой собственный протокол где сначала n
байт - это размер файла, который следует, а затем вы знаете, сколько данных ожидать от следующего элемента. Или откройте новое соединение для каждого элемента (recv()
на сокете, другая сторона которого была закрыта, не блокируется и выдает b''
).
Кстати, последний комментарий также означает, что после отправки последнего изображения, сервер может сделать conn.close()
и отключиться (или прослушать новые входящие соединения), и мы можем сделать еще одно изменение во фрагменте выше, а именно:
pack += s.recv(bufsize)
скажем:
buf = s.recv(bufsize)
if not buf:
s.close()
break # end the "while True" loop
pack += buf
, чтобы также перестать получать на стороне клиента.
Также одна заметка относительно учебника, который вы упомянули. В тривиальных случаях ... например, при отправке коротких строковых сообщений, хотя вы не должны на это полагаться, вам часто везет и recv
все ожидаемые данные в одном куске.