DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
Сеть всегда непредсказуема. TCP избавляет вас от многих из этих случайных действий. Одна замечательная вещь, которую делает TCP: он гарантирует, что байты прибудут в том же порядке. Но! Это не гарантирует, что они будут доставлены таким же образом измельченными. Вы просто не можете предположить, что каждый send () с одного конца соединения приведет к ровно одному recv () на дальнем конце с точно таким же количеством байтов.
Когда вы говорите socket.recv (x)
, вы говорите «не возвращайтесь, пока не прочтете x байтов из сокета». Это называется «блокирование ввода-вывода»: вы будете блокировать (ждать), пока ваш запрос не будет выполнен. Если каждое сообщение в вашем протоколе содержит ровно 1024 байта, вызов socket.recv (1024)
будет работать отлично. Но похоже, что это неправда. Если ваши сообщения имеют фиксированное количество байтов, просто передайте это число в socket.recv ()
и все готово.
Но что, если ваши сообщения могут иметь разную длину? Первое, что вам нужно сделать: прекратить вызов socket.recv ()
с явным номером. Изменив это:
data = self.request.recv(1024)
на это:
data = self.request.recv()
означает, что recv ()
всегда будет возвращаться всякий раз, когда получит новые данные.
Но теперь у вас есть новая проблема: как узнать, что отправитель получил отправил вам полное сообщение? Ответ: нет. Вам нужно будет сделать длину сообщения явной частью вашего протокола. Вот лучший способ: добавляйте к каждому сообщению длину, либо как целое число фиксированного размера (преобразованное в сетевой порядок байтов с использованием socket.ntohs ()
или socket.ntohl ()
пожалуйста!), либо как строка, за которой следует некоторый разделитель (например, '123:'). Этот второй подход часто менее эффективен, но в Python он проще.
После того, как вы добавили его в свой протокол, вам нужно изменить свой код для обработки recv ()
, возвращающей произвольные объемы данных в любой момент. время. Вот пример того, как это сделать. Я попытался написать это как псевдокод или с комментариями, чтобы рассказать вам, что делать, но это было не очень понятно. Итак, я написал это явно, используя префикс длины как строку цифр, заканчивающуюся двоеточием. Вот, пожалуйста:
length = None
buffer = ""
while True:
data += self.request.recv()
if not data:
break
buffer += data
while True:
if length is None:
if ':' not in buffer:
break
# remove the length bytes from the front of buffer
# leave any remaining bytes in the buffer!
length_str, ignored, buffer = buffer.partition(':')
length = int(length_str)
if len(buffer) < length:
break
# split off the full message from the remaining bytes
# leave any remaining bytes in the buffer!
message = buffer[:length]
buffer = buffer[length:]
length = None
# PROCESS MESSAGE HERE
Такова природа TCP: протокол заполняет пакеты (нижний уровень - это IP-пакеты) и отправляет их. Вы можете иметь некоторую степень контроля над MTU (Maximum Transfer Unit).
Другими словами: вы должны разработать протокол, который работает поверх TCP, в котором определено ваше «разграничение полезной нагрузки». Под «разграничением полезной нагрузки» я подразумеваю способ извлечения единицы сообщения, поддерживаемой вашим протоколом. Это может быть так же просто, как «каждая строка с завершающим NULL».
В ответе Ларри Гастингса есть несколько отличных общих советов по поводу сокетов, но есть пара ошибок, связанных с тем, как метод recv (bufsize)
работает в Модуль сокета Python.
Итак, чтобы уточнить, поскольку это может сбивать с толку других, которые обращаются к нему за помощью:
recv (bufsize)
не является необязательным. Вы получите сообщение об ошибке, если вызовете recv ()
(без параметра). recv (bufsize)
имеет максимальный размер . . Recv с радостью вернет меньше байтов, если их будет меньше. См. документацию для подробностей.
Теперь, если вы получаете данные от клиента и хотите знать, когда вы получил все данные, вы ' re, вероятно, придется добавить его в свой протокол - как предлагает Ларри. См. этот рецепт , чтобы узнать о стратегиях определения конца сообщения.
Как указано в этом рецепте, для некоторых протоколов клиент просто отключится, когда закончит отправку данных. В таких случаях ваш цикл while True
должен работать нормально. Если клиент , а не отключается, вам нужно придумать способ обозначить длину вашего контента, разграничить сообщения или реализовать тайм-аут.
Я буду рад помочь вам в дальнейшем если бы вы могли опубликовать точный код клиента и описание вашего протокола тестирования.
клиент просто отключится, когда закончит отправку данных. В таких случаях ваш цикл while True
должен работать нормально. Если клиент , а не отключается, вам нужно придумать какой-нибудь способ сигнализировать о длине вашего контента, разграничить сообщения или реализовать тайм-аут.
Я буду рад попытаться помочь в дальнейшем если бы вы могли опубликовать точный код клиента и описание вашего протокола тестирования.
клиент просто отключится, когда закончит отправку данных. В таких случаях ваш цикл while True
должен работать нормально. Если клиент , а не отключается, вам нужно придумать какой-нибудь способ сигнализировать о длине вашего контента, разграничить сообщения или реализовать тайм-аут.
Я буду рад попытаться помочь в дальнейшем если бы вы могли опубликовать точный код клиента и описание вашего протокола тестирования.
В качестве альтернативы вы можете использовать recv (x_bytes, socket.MSG_WAITALL)
, который, кажется, работает только в Unix и вернет точно x_bytes
.