【问题标题】:variable length packets in phpphp中的可变长度数据包
【发布时间】:2010-10-04 08:33:12
【问题描述】:

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

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

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

提前致谢。

【问题讨论】:

    标签: php sockets


    【解决方案1】:

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

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

    注意:socket_read() 返回零 长度字符串 ("") 当没有 更多数据要读取。

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

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

    【讨论】:

      【解决方案2】:

      你有没有尝试过这样的事情:

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

      【讨论】:

      • 有没有办法从使用 socket_create 创建的句柄中获取未读字节? socket_get_status 是 fsockopen 唯一的函数。
      【解决方案3】:

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

      谨慎使用 UDP,因为如果您尝试将多个读取流式传输到一条消息中,您也不能保证读取数据包的顺序是对等方发送的顺序。在这种情况下建议使用 TCP 套接字。

      【讨论】:

      • 我必须使用 UDP。问题不在于知道消息何时应该结束,而是如果我指定的长度太大,读取就会挂起并等待下一个数据包到达。如果我指定小长度,则只读取一小部分数据,其余部分被丢弃。
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 2011-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-22
        • 1970-01-01
        • 1970-01-01
        • 2011-05-29
        • 2014-08-30
        相关资源
        最近更新 更多