views:

676

answers:

4

I am receiving packets sent to my server through UDP. I am using socket_read to read the data and it is coming along just fine. I have run into an error however. The length parameter to socket_read in my case is NOT always the same. The length of the data can range anywhere from 50-150 bytes. One thing that remains constant is that the data set is ended with a \x00 byte. How would I get the read function to always read until encountering this byte? I have already tried PHP_NORMAL_READ flag, but the docs say it only ends at \n or \r which really isn't what I want (tried it it doesn't work for my data). At the same time, the php page for socket_read states in the length parameter description that,

The maximum number of bytes read is specified by the length parameter. Otherwise you can use \r, \n, or \0 to end reading (depending on the type parameter, see below).

The type says nothing about the /0 byte. Its like a piece of documentation is missing. What I need is a function that will either let me specify a delimiter for my data, will automatically read all the data from the socket that is available. There might be a solution in the socket_recv function but its undocumented and I don't know how it works.

Thanks in advance.

A: 

Application dealing with the read payload will need to recognize when you have reached "end of record" for whatever application message you are passing. Expect arbitrary length on read.

Careful with use of UDP, as you can not guarantee order of packets read are order sent by peer either, if you are trying to stream several reads into a message. Recommend use of TCP socket in this case.

Sean
I have to use UDP. The problem is not with knowing when the end of the message should be, but if I specify too large of a length, the read gets hung up and waits for the next packets to arrive. If I specify to small of a length, only a small part of the data is read and the rest is thrown out.
Samuel
A: 

Hav you tried something like this:

do {
    echo socket_read($handle,1024);
    $status = socket_get_status($handle);
} while($status['unread_bytes']);
Tim
is there a way to get unread bytes from a handle created with socket_create? socket_get_status is a fsockopen only function.
Samuel
A: 

Came across another approach that might just work in your case:

<?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;
  }
?>

The most interesting part about this approach is the:

do
...
while(strlen($buffer) == 516);  // the first non-full packet is the last.
Tim
A: 

If I understand correctly, you want to read data from a socket until there is no more data to read, with the problem being that the amount of data is variable and you don't know when to stop.

According to the relevant manual page (http://php.net/socket_read):

Note: socket_read() returns a zero length string ("") when there is no more data to read.

You should be able to deal with variable-length data by reading byte-by-byte until you hit a zero-length string:

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