NotionCommotion Posted April 27, 2017 Share Posted April 27, 2017 While this work, it doesn't seem right. Please see my comments. Thanks <?php $fp = fsockopen("73.11.165.217", 1337, $errno, $errstr, 30); $msg=json_encode(['method'=>'test']); $lng=pack("V", strlen($msg)); $out=$lng.$msg; fwrite($fp, $out); $prefix=fgets($fp, 5); //Why not just 4? $lng = unpack('Vlen', $prefix)['len']; //Is buffering handled by PHP? $rsp=fgets($fp, $lng+1); //Why +1? fclose($fp); print_r(json_decode($rsp)); Output stdClass Object ( [result] => success [id] => 123 ) Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/ Share on other sites More sharing options...
requinix Posted April 27, 2017 Share Posted April 27, 2017 4 should be right, there is no buffering involved, and you shouldn't need a +1. Why did you do those things? var_dump(bin2hex($prefix)); // should be 0000xxyy, length = 256 * xx + yy var_dump("*" . $rsp . "*"); // should be a complete json string *{"result":"success","id":123}* Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545908 Share on other sites More sharing options...
NotionCommotion Posted April 27, 2017 Author Share Posted April 27, 2017 I know, something is not right. Note that I am using "V" with pack() which is unsigned long (always 32 bit, little endian byte order), so expected prefix is different than you showed. It shows up as xxyy0000. Looking at https://en.wikipedia.org/wiki/Endianness, it appears that "maybe" it should be yyxx0000? This.... $msg=json_encode(['method'=>'test','params'=>['guid'=>$config['guid']],'id'=>1]); echo('$msg='); var_dump($msg); $lng=pack("V", strlen($msg)); echo('bin2hex($lng)='); var_dump(bin2hex($lng)); fwrite($fp, $lng.$msg); $prefix=fgets($fp, 4); //Why not just 4? echo('bin2hex($prefix)='); var_dump(bin2hex($prefix)); // should be 0000xxyy, length = 256 * xx + yy $lng = unpack('Vlen', $prefix)['len']; echo('$lng='); var_dump($lng); $rsp=fgets($fp, $lng+0); //Why +1? echo('$rsp='); var_dump("*" . $rsp . "*"); $rsp=json_decode($rsp)->result; fclose($fp); produces the following. Obviously, the important part is unpack(): Type V: not enough input, need 4, have 3. $msg=string(81) "{"method":"test","params":{"guid":"0b74085b-03c9-4c2a-997f-fa554451a46c"},"id":1}" bin2hex($lng)=string( "51000000" bin2hex($prefix)=string(6) "170000" <br /> <b>Warning</b>: unpack(): Type V: not enough input, need 4, have 3 in <b>/var/www/html/index.php</b> on line <b>129</b><br /> $lng=NULL <br /> <b>Warning</b>: fgets(): Length parameter must be greater than 0 in <b>/var/www/html/index.php</b> on line <b>132</b><br /> $rsp=string(2) "**" <br /> <b>Notice</b>: Trying to get property of non-object in <b>/var/www/html/index.php</b> on line <b>135</b><br /> But when I only change 4 to 5 and add +1. $msg=json_encode(['method'=>'test','params'=>['guid'=>$config['guid']],'id'=>1]); echo('$msg='); var_dump($msg); $lng=pack("V", strlen($msg)); echo('bin2hex($lng)='); var_dump(bin2hex($lng)); fwrite($fp, $lng.$msg); $prefix=fgets($fp, 5); //Why not just 4? echo('bin2hex($prefix)='); var_dump(bin2hex($prefix)); // should be 0000xxyy, length = 256 * xx + yy $lng = unpack('Vlen', $prefix)['len']; echo('$lng='); var_dump($lng); $rsp=fgets($fp, $lng+1); //Why +1? echo('$rsp='); var_dump("*" . $rsp . "*"); $rsp=json_decode($rsp)->result; fclose($fp); produces this... $msg=string(81) "{"method":"test","params":{"guid":"0b74085b-03c9-4c2a-997f-fa554451a46c"},"id":1}" bin2hex($lng)=string( "51000000" bin2hex($prefix)=string( "17000000" $lng=int(23) $rsp=string(25) "*{"result":"0123456789"}*" Wireshark on this client appears to show correct data being received from the server. The only place the server ever writes is below, and all appears to be correct. public function send($msg){ //Do I need to parse??? Still need to implement drain if($this->isConnected()) { if($this->parseJson) { $msg=json_encode($msg); } if(!$this->socket->write(pack("V", strlen($msg)).$msg)) { syslog(LOG_ERR,"LengthPrefixStream::send() didn't write"); } return true; } else { syslog(LOG_ERR,"LengthPrefixStream::send() not connected (should never happen). ".$msg); return false; } } Any ideas where I should start looking? Thanks Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545913 Share on other sites More sharing options...
NotionCommotion Posted April 27, 2017 Author Share Posted April 27, 2017 More information. I just confirmed with the c++ client programmer that he didn't need to do my hack of adding the extra byte. As such, I am 99% confident it has nothing to do with the server script. Hopefully, I am not over confident Side note. Is it common to suppress errors/warnings for @fsockopen()? While I didn't show it on my original post, I check for false and do the error check as described by the http://php.net/manual/en/function.fsockopen.php examples. Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545914 Share on other sites More sharing options...
requinix Posted April 27, 2017 Share Posted April 27, 2017 Note that I am using "V" with pack() which is unsigned long (always 32 bit, little endian byte order), so expected prefix is different than you showed.Yeah, I knew it was LE but got it backwards in my post yyxx0000 is correct I wouldn't have expected fragmentation with such small packets... Try with blocking. $fp = fsockopen(...); stream_set_blocking($fp, true);And no, I don't think it's normal to suppress errors on fsockopen: it's a call that should succeed and won't issue warnings with normal usage so I don't think @ is appropriate. And a small correction - or at least what I think is a correction. There is a small bit of buffering done by PHP and/or the OS: when a packet arrives it does get buffered somewhere before it's read by the application (otherwise it would be lost, obviously). But that's more of a networking thing that it is a streams thing, so I wasn't considering that when I said there is no buffering involved. Technical detail. Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545918 Share on other sites More sharing options...
NotionCommotion Posted April 27, 2017 Author Share Posted April 27, 2017 No change in results Wasn't thinking. Of course yyxx0000. Testing server is set up to display warnings which causes fsockopen to issue a warning upon not being able to connect. Would be nice to be able to use some version of @ to suppress warnings and not errors, but don't think it is possible. Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545919 Share on other sites More sharing options...
requinix Posted April 27, 2017 Share Posted April 27, 2017 Hmm. Okay. Forget parsing the returned data - just dump everything you get until the connection closes. Keep the blocking in. while (!feof($fp)) { var_dump(bin2hex(fgets($fp))); } Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545923 Share on other sites More sharing options...
Solution kicken Posted April 27, 2017 Solution Share Posted April 27, 2017 (edited) You should be using fread($fp, 4), not fgets. fgets stops reading on new lines which might exist in your binary representation of your length. For example if your length were 266 that'd be encoded as 0A010000. 0A is the byte for a new line so fgets would stop reading there and return only 1 bytes rather than the 4 you requested. Always use fread() if you want a specific number of bytes read. Only use fgets if you want the special "read until end of line" behavior. Also you always need to check the return value of your read to see how much was read. Even with blocking operations it's possible for a read to return less data than you requested. Edited April 27, 2017 by kicken 2 Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545931 Share on other sites More sharing options...
NotionCommotion Posted April 28, 2017 Author Share Posted April 28, 2017 My bad. I looked at the first http://php.net/manual/en/function.fsockopen.php example and thought I was an expert. fgets, fread, potato pototo, tomato, tomoto... What's the difference? Evidently a lot! Quote Link to comment https://forums.phpfreaks.com/topic/303810-how-to-retrieve-results-from-a-stream/#findComment-1545945 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.