Read constant UDP stream in php - php

how do i go about reading data being sent almost constantly to my server.
the protocol is udp. if i try to read in a while(1) loop, i dont get anything. it seems like the read will only echo once all the reading is done. so it waits till the loop is done reading which it will never be. i want the socket_read to echo immediately when it gets the data. here is the code that doesnt work. thanks in advance.
<?php
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock, $local, $port) or die('Could not bind to address');
//this is where the reading loop should go.
while(1)
{
echo socket_read($sock,1024);
}
socket_close($sock);
?>

Try calling flush() immediately after that echo statement.

Something like this might help:
do {
echo socket_read($handle,1024);
$status = socket_get_status($handle);
} while($status['unread_bytes']);
OR
while ( $buffer = #socket_read($sock,512,PHP_NORMAL_READ) )
echo $buffer;

The PHP manual entry on socket_read() is a little vague when it comes to how much (if any) internal buffering it's doing. Given that you are passing 1024 in for the length, that specifies that it should return after receiving no more than 1024 bytes of data.
Disclaimer: the following is just speculation, as I have no knowledge of the internal implementation of socket_read().
If the socket_read() function is using its length parameter as a hint for an internal buffer size, you might see bad performance with small UDP packets. For example, if socket_read() waits for 1024 bytes of data regardless of the size of the packets, if you are constantly receiving 60 byte UDP packets it'll take a while for the buffer to fill and the function to return.
(Note: after looking up the "unread_bytes" field mentioned by Tim, it looks like PHP does keep internal buffers, but it makes no mention of how large or small those might be.)
In this case, socket_read() will return larger chunks of data once its buffers fill to reduce processing resource consumption, but at the expense of higher latency. If you need the packets as past as possible, perhaps setting a lower length field would work. That would force socket_read() to return sooner, albeit at the expense of executing your loop more often. Also if you set the length too low, your socket_read()'s might start returning incomplete packets, so you'll have to account for that in your code. (If that matters for your application, of course.)

I needed to call ob_flush();. Never even heard of it before. turns out my problem wasn't the loop, but the fact that php naturally waits till script is done before actually sending the internal buffer to the web browser. calling flush(); followed by ob_flush(); will force php to send whatever buffer it has stored to the browser immediately. This is needed for scripts that will not stop (infinite loops) and want to echo data to the browser. Sometimes flush() doesn't work as it didn't in this case. Hope that helps.

Related

How to show all output from fread socket unix in PHP?

I try show output from socket but the return is showed cut.
<?php
$socket = '/var/run/qemu-server/121.serial1';
$sock = stream_socket_client('unix://'.$socket, $errno, $errstr);
fwrite($sock, $argv[1] . "\r\n");
$data = '';
while ($buffer = fread($sock, 8128)) $data .= $buffer;
echo $data;
fclose($sock);
?>
I need this output:
{"VMid":"121","Command":"ls /","Output":"bin\nboot\ndev\netc\nhome\nlib\nlib32\nlib64\nlibx32\nlost+found\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nsnap\nsrv\nswap.img\nsys\ntmp\nusr\nvar\n"}
But it only returns:
{"VMid":"121","Command":"ls /","Output"
I tried "stream_set_read_buffer", "file_get_contents" and no success.
I presume here that the server has not had time to fully respond by the time you are polling. You can quickly test this theory by putting a sleep() after you send the instruction (fwrite) before you poll (fread). That's a test solution, not final (as you never know how long to "sleep" for).
What you need for sockets generally are a continuous poll (while loop that basically never ends, but under control so you can pause / exit etc), and continuous buffer read/write (append new content to a buffer; when you either reach the end of expected message OR you read the number of bytes you expect* remove that content from the front of the buffer and leave the remainder for next loop. You can, of course, bomb out at this point if you have everything you need and close the socket or return to polling later.
A common trick is to set the first two/four bytes of the message to the length of the payload, then the payload. So you constantly would poll for those two/four bytes and then read the content based of that. Probably not possible with another system like QEMU, so you'll need to look instead for...? EOL/NL etc?

PHP unread_bytes work in PHP 5.3 but not in PHP 5.4

I have a problem with a connection to a telnet-server using PHP sockets. I've a finished telnet class, but on my other server did that class not work because of the stream_get_meta_data unread_bytes value. Does PHP have changed that in Version 5.4? I can't find what about this change.
The code that i use:
$buff = '';
while (!feof($this->socket)) {
$buff .= fread($this->socket, 1024);
$stream_meta_data = stream_get_meta_data($this->socket);
if ($stream_meta_data['unread_bytes'] <= 0)
break;
}
Can anyone help me or say me, what can i change?
You didn't clearly state what your code snippet is supposed to do:
read bytes until the socket connection is shut down, or
read bytes that are available at the moment, on a live connection.
But your comment feof() dont work correctly suggests that you're after 2., since a feof() check would be sufficient for 1.; cf. the comment from Wez to the "Not a bug" unread_bytes always 0:
unread_bytes is the number of bytes remaining in PHPs buffering layer
after the last read.
If you have consumed all data from the buffer
on a prior read, unread_bytes will remain at zero until you next read
a chunk of data from the network.
So, unread_bytes should not be
used to determine if more data is pending; you should use either:
feof() to detect end of file.
Don't forget that you
can use non-blocking mode here. PHP 4.3 has a new function
called stream_select() which behaves like socket_select() from the
sockets extension, but works on all files returned by fopen() and
fsockopen(). You can use it to test which files are ready for
reading/writing and also specify a timeout.
So, if you want 2., you can use stream_select() or socket_select().

PHP Output Buffer "Millenium" Bug?

I faced a strange issue today.
For several months I used buffer flushing in PHP to send small string sizes to the client without problems.
Today I returned to the project and it turned out that my server won't send strings smaller than 512 bytes.
Here is my code:
<?php
echo "length:".$myUpcomingStringSize;
ob_flush();
flush();
sleep(1);
for($i = 0; $i < count($allLines); $++) {
echo $allLines[$i];
ob_flush();
flush();
}
?>
This code worked like charm the whole last year. And now it doesn't anymore. I played around a bit and added some random characters. As the string size gets equal or greater 512, the server sends the buffer content.
Can anybody imagine the issue I have to solve here? Anyone else facing this issue? Or does
someone know how to configure this minimum packet size?
If you changed neither the program nor the server, you should assume that the program never worked as intended. Especially Windows systems are known to buffer the output until a certain number of Bytes is in the output buffer. This buffering is at system-level and thus can not be affected by any PHP configuration.
If you know that 512 Bytes is the minimum required for the output buffer to send, then you could use something like
define('MIN_OUTPUT_LENGTH', 512);
echo str_pad("length: $myUpcomingStringSize", MIN_OUTPUT_LENGTH, "\0"), '\n';
// (If you run into trouble with the null-bytes, use space character instead)
Notes
If you do not use "userspace" output buffering, then ob_flush(); is redundant.
If there is no delay in your for loop, then flushing between lines is not a good idea. Especially for mobile applications where the network tries to pack as much data as possible into a single packet.
There is a syntax error in your for loop header (The expression $++ is missing a variable identifier, probably i)

How to determine socket resource has completed buffering?

Firing a command to socket resource and getting the output takes some decent amount of time in PHP.
I have written code to read the buffered output string after sleep duration of 1 second and it works fine.
If i don't provide any delay after fputs, i don't get any string.
How to determine this time? putting time duration by hit and trial can cause trouble.
For safe side i always put time in seconds.
What parameters affect this time, does anyone has statistical data?
$socket = fsockopen($ip,3083);
$command = 'RTRV-NE-GEN:::123;';
fputs($socket,$command);
sleep(1);
$string = fread( $socket, 3000 );
You probably just need to do fflush($socket); there after you do fputs(...).

This loop won't echo my string

I have an infinite loop that I want to sleep for a second but the browser just hangs and nothing echos. Can someone tell me why?
while(1)
{
sleep(1);
echo 'test'.'<br>';
}
It won't work until the server stops processing.
You could try flushing the output buffer with flush(), but it's not guaranteed to work.
Try this function from PHP.net:
function flush_buffers() {
ob_end_flush();
ob_flush();
flush();
ob_start();
}
That's because PHP sends data to browser in big chunks. It is all about optimization, sending small data is bad for performance, you want it to be sent in huge enough blocks so overhead from transferring it (both in speed and actual traffic) would be relatively low. Couple of small strings is just not big enough. Try add a flush() right after the echo, it will force PHP send this string to the browser.
Couse it's a infinite loop it never will send response or be break

Categories