Читайте из сокета: это, как гарантируют, по крайней мере, получит x байты?

Время компиляции ColdFusion

  1. для больших Форм Flash.
  2. Типы Динамической переменной (Иногда я ненавижу их.)
  3. Отсутствие функций в CFScript.
  4. CFTable (Никогда не может заставлять его отображать право).
  5. отсутствие типов диаграммы упущено из CFChart.
  6. Полное отсутствие поддержки NTLM (готовое предприятие - да право)
  7. Слабоумный обзор var в CFCs
  8. Никакое понятие истинного ПУСТОГО УКАЗАТЕЛЯ - Ваша переменная просто исчезает!
  9. Никакой способ протестировать на существование определенных вещей (как объемы, просто участники в них)
5
задан Jonathan Leffler 9 August 2009 в 15:45
поделиться

7 ответов

Полагаю, вы используете TCP. TCP - это протокол, основанный на потоках, без понятия о границах пакетов или сообщений.

Это означает, что при чтении вы можете получить меньше байтов, чем запрашиваете. Если ваши данные составляют, например, 128 КБ, вы можете получить только 24 КБ при первом чтении, требуя повторного чтения, чтобы получить остальные данные.

Например, в C:

int read_data(int sock, int size, unsigned char *buf) {
   int bytes_read = 0, len = 0;
   while (bytes_read < size && 
         ((len = recv(sock, buf + bytes_read,size-bytes_read, 0)) > 0)) {
       bytes_read += len;
   }
   if (len == 0 || len < 0) doerror();
   return bytes_read;
}
13
ответ дан 18 December 2019 в 05:33
поделиться

Насколько я знаю, такое поведение вполне разумно. Сокеты могут и, вероятно, будут фрагментировать ваши данные при их передаче. Вы должны быть готовы обрабатывать такие случаи, применяя соответствующие методы буферизации.

С другой стороны, если вы передаете данные на локальном хосте и действительно получаете только 4 байта, это, вероятно, означает, что у вас есть ошибка где-то еще в вашем коде. .

РЕДАКТИРОВАТЬ: Идея - попробуйте запустить сниффер пакетов и посмотреть, будет ли переданный пакет полон или нет; это может дать вам некоторое представление о том, обнаруживается ли ошибка в вашем клиенте или на сервере.

9
ответ дан 18 December 2019 в 05:33
поделиться

Простой ответ на ваш вопрос «Чтение из сокета: гарантировано ли получение хотя бы x байтов?» - нет . Посмотрите на строки документации для этих методов сокета:

>>> import socket
>>> s = socket.socket()
>>> print s.recv.__doc__
recv(buffersize[, flags]) -> data

Receive up to buffersize bytes from the socket.  For the optional flags
argument, see the Unix manual.  When no data is available, block until
at least one byte is available or until the remote end is closed.  When
the remote end is closed and all data is read, return the empty string.
>>> 
>>> print s.settimeout.__doc__
settimeout(timeout)

Set a timeout on socket operations.  'timeout' can be a float,
giving in seconds, or None.  Setting a timeout of None disables
the timeout feature and is equivalent to setblocking(1).
Setting a timeout of zero is the same as setblocking(0).
>>> 
>>> print s.setblocking.__doc__
setblocking(flag)

Set the socket to blocking (flag is true) or non-blocking (false).
setblocking(True) is equivalent to settimeout(None);
setblocking(False) is equivalent to settimeout(0.0).

Из этого ясно, что recv () не требуется для возврата столько байтов, сколько вы просили. Кроме того, поскольку вы вызываете settimeout (10.0) , возможно, что некоторые, но не все, данные будут получены ближе к истечению срока действия recv () . В этом случае recv () вернет то, что он прочитал - что будет меньше, чем вы просили (но постоянство <4 байтов кажется маловероятным).

Вы упоминаете дейтаграмму в вашем вопросе, который подразумевает, что вы используете (без установления соединения) сокеты UDP (не TCP). Различие описано здесь . Опубликованный код не показывает создание сокета, поэтому мы можем только догадываться здесь, однако эта деталь может быть важной. Может помочь, если вы разместите более полный образец своего кода.

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

5
ответ дан 18 December 2019 в 05:33
поделиться

Из справочной страницы Linux recv http://linux.about.com /library/cmd/blcmdl2_recv.htm:

Вызовы приема обычно возвращают любые данные доступны, до запрошенных сумма, а не ждать получение всей запрошенной суммы.

Итак, если ваш отправитель все еще передает байты, вызов даст только то, что было передано до сих пор.

1
ответ дан 18 December 2019 в 05:33
поделиться

Именно так работает TCP. Вы не получите сразу все данные. Существует слишком много проблем с синхронизацией между отправителем и получателем, включая операционную систему отправителя, сетевую карту, маршрутизаторы, коммутаторы, сами провода, сетевую карту получателя, ОС и т. Д. В аппаратном обеспечении и в ОС есть буферы.

Вы не можете предположить, что сеть TCP - это то же самое, что и канал ОС. С pipe - это все программное обеспечение, поэтому для большинства сообщений не нужно платить за доставку всего сообщения сразу. Что касается сети, вы должны предположить, что будут проблемы с синхронизацией даже в простой сети.

Вот почему recv () не может предоставить вам все данные сразу, он может просто быть недоступен, даже если все работает правильно. Обычно вы вызываете recv () и перехватываете вывод. Это должно сказать вам, сколько байтов у вас получил. Если оно меньше, чем вы ожидаете, вам нужно продолжать вызывать recv () (как было предложено), пока вы не получите правильное количество байтов. Имейте в виду, что в большинстве случаев recv () возвращает -1 при ошибке, поэтому проверьте это и проверьте свою документацию на наличие значений ERRNO. В частности, EAGAIN создает проблемы для людей. Вы можете прочитать об этом в Интернете, чтобы узнать подробности, но, насколько я помню, это означает, что в настоящий момент нет данных, и вам следует попробовать еще раз.

Кроме того, из вашего сообщения похоже, что вы уверены, что отправитель отправляет данные, которые вам нужно отправить, но для полноты проверьте это: так что проверьте это и проверьте свою документацию на значения ERRNO. В частности, EAGAIN создает проблемы для людей. Вы можете прочитать об этом в Интернете, чтобы узнать подробности, но, насколько я помню, это означает, что в настоящий момент нет данных, и вам следует попробовать еще раз.

Кроме того, из вашего сообщения похоже, что вы уверены, что отправитель отправляет данные, которые вам нужно отправить, но для полноты проверьте это: так что проверьте это и проверьте свою документацию на значения ERRNO. В частности, EAGAIN создает проблемы для людей. Вы можете прочитать об этом в Интернете, чтобы узнать подробности, но, насколько я помню, это означает, что в настоящий момент нет данных, и вам следует попробовать еще раз.

Кроме того, из вашего сообщения похоже, что вы уверены, что отправитель отправляет данные, которые вам нужно отправить, но для полноты проверьте это: http://beej.us/guide/bgnet/output/html/multipage/advanced.html#sendall

Вы должны сделать что-то подобное на конце recv () для обработки частичных приемов. Если у вас фиксированный размер пакета, вы должны читать, пока не получите ожидаемый объем данных. Если у вас переменный размер пакета, вы должны читать до тех пор, пока не получите заголовок, который сообщает вам, сколько данных вы отправляете (), а затем читать гораздо больше данных.

3
ответ дан 18 December 2019 в 05:33
поделиться

Если отправитель отправляет 515 байтов, а ваш BUFSIZE равен 512, то первое recv вернет 512 байтов, а следующее - 3 байта ... Может это быть тем, что происходит?

(Это всего лишь один из многих случаев, которые приводят к получению 3-байтового recv из более крупной посылки ...)

1
ответ дан 18 December 2019 в 05:33
поделиться

Если вам все еще интересно, используйте шаблоны вроде этого:

# 4 bytes are needed here ......
# read remainder of datagram...

может создать глупую штуку с окном.

Отметьте это вне

1
ответ дан 18 December 2019 в 05:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: