php中的可变长度数据包

时间:2009-01-29 21:20:26

标签: php sockets

我正在接收通过UDP发送到我的服务器的数据包。我正在使用socket_read来读取数据并且它正好相应。但是我遇到了一个错误。在我的情况下,socket_read的长度参数并不总是相同的。数据长度范围为50-150字节。保持不变的一件事是数据集以\ x00字节结束。在遇到这个字节之前,如何让read函数始终读取?我已经尝试过PHP_NORMAL_READ标志,但文档说它只在\ n或\ r \ n结束,这真的不是我想要的(试过它对我的数据不起作用)。同时,socket_read的php页面在 length 参数描述中声明,

  

读取的最大字节数为   由length参数指定。   否则,您可以使用\ r,\ n或\ 0来   结束阅读(取决于类型   参数,见下文)。

该类型没有说明/ 0字节。它就像缺少一份文件。我需要的是一个函数,它将让我为我的数据指定一个分隔符,将自动从可用的套接字读取所有数据。 socket_recv函数中可能有一个解决方案,但它没有文档,我不知道它是如何工作的。

提前致谢。

4 个答案:

答案 0 :(得分:4)

如果我理解正确,你想从套接字中读取数据,直到没有更多数据要读取,问题是数据量是可变的,你不知道何时停止。

根据相关手册页(http://php.net/socket_read):

  

注意:socket_read()返回零   长度字符串(“”)没有时   更多要阅读的数据。

您应该能够通过逐字节读取来处理可变长度数据,直到您达到零长度字符串:

while (($currentByte = socket_read($socket, 1)) != "") {
    // Do whatever you wish with the current byte
}

答案 1 :(得分:0)

处理读取有效负载的应用程序需要识别何时到达“记录结束”以查找正在传递的任何应用程序消息。阅读时期望任意长度。

小心使用UDP,因为如果您尝试将多个读取流式传输到消息中,则无法保证读取的数据包的顺序是由对等方发送的顺序。在这种情况下,建议使用TCP套接字。

答案 2 :(得分:0)

你试过这样的事情:

do {
    echo socket_read($handle,1024);
    $status = socket_get_status($handle);
} while($status['unread_bytes']);

答案 3 :(得分:0)

遇到了另一种可能适用于您的方法:

<?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.