пакеты переменной длины в php - PullRequest
4 голосов
/ 30 января 2009

Я получаю пакеты, отправленные на мой сервер через UDP. Я использую socket_read для чтения данных, и все идет хорошо. Я столкнулся с ошибкой, однако. Параметр длины для socket_read в моем случае НЕ всегда одинаков. Длина данных может варьироваться от 50 до 150 байт. Одна вещь, которая остается постоянной, состоит в том, что набор данных заканчивается байтом \ x00. Как бы заставить функцию чтения всегда читать до встречи с этим байтом? Я уже пробовал флаг PHP_NORMAL_READ, но в документах говорится, что он заканчивается только на \ n или \ r, что на самом деле не то, что я хочу (пробовал, но это не работает для моих данных). В то же время, страница php для socket_read сообщает в описании параметра length , что

Максимальное количество прочитанных байтов определяется параметром длины. В противном случае вы можете использовать \ r, \ n или \ 0 для конец чтения (в зависимости от типа параметр, см. ниже).

Тип ничего не говорит о байте / 0. Это как кусок документации отсутствует. Что мне нужно, так это функция, которая либо позволит мне указать разделитель для моих данных, автоматически прочитает все данные из доступного сокета. Возможно, есть решение в функции socket_recv, но оно недокументировано, и я не знаю, как оно работает.

Заранее спасибо.

Ответы [ 4 ]

4 голосов
/ 13 февраля 2009

Если я правильно понимаю, вы хотите читать данные из сокета до тех пор, пока не останется больше данных для чтения, проблема в том, что объем данных является переменным, и вы не знаете, когда остановиться.

Согласно соответствующей странице руководства (http://php.net/socket_read):

Примечание: socket_read () возвращает ноль длина строки (""), когда нет больше данных для чтения.

Вы должны иметь возможность работать с данными переменной длины, читая побайтно, пока не достигнете строки нулевой длины:

while (($currentByte = socket_read($socket, 1)) != "") {
    // Do whatever you wish with the current byte
}
0 голосов
/ 30 января 2009

Вы пробовали что-то вроде этого:

do {
    echo socket_read($handle,1024);
    $status = socket_get_status($handle);
} while($status['unread_bytes']);
0 голосов
/ 02 февраля 2009

Наткнулся на другой подход, который может сработать в вашем случае:

<?php
  function tftp_fetch($host, $filename)
  {
    $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);

    // create the request packet
    $packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
    // UDP is connectionless, so we just send on it.
    socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);

    $buffer = '';
    $port = '';
    $ret = '';
    do
    {
      // $buffer and $port both come back with information for the ack
      // 516 = 4 bytes for the header + 512 bytes of data
      socket_recvfrom($socket, $buffer, 516, 0, $host, $port);

      // add the block number from the data packet to the ack packet
      $packet = chr(0) . chr(4) . substr($buffer, 2, 2);
      // send ack
      socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);

      // append the data to the return variable
      // for large files this function should take a file handle as an arg
      $ret .= substr($buffer, 4);
    }
    while(strlen($buffer) == 516);  // the first non-full packet is the last.
    return $ret;
  }
?>

Самая интересная часть этого подхода:

do
...
while(strlen($buffer) == 516);  // the first non-full packet is the last.
0 голосов
/ 30 января 2009

Приложение, работающее с полезной нагрузкой чтения, должно будет распознать, когда вы достигли «конца записи» для любого сообщения приложения, которое вы передаете. Ожидайте произвольную длину при чтении.

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

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