I'm looking for solution to read and process message from stream within created socket server.
I've come to this:
$server = stream_socket_server("tcp://0.0.0.0:8000", $errno, $errorMessage);
for (;;)
{
$client = #stream_socket_accept($server);
if ($client)
{
echo 'Connection accepted from '.stream_socket_get_name($client, false) . "n";
stream_copy_to_stream($client, $client);
fclose($client);
}
}
which simply echoes whatever is sent to stream. I cannot find out what do I need to do, say, between stream_socket_accept() and fclose() to get contents of message and act upon it. Any help? Thanks in advance.
Related
Hi I'm trying server sent events(SSE) using php, I have a https url where I get the live streaming data. Below is my script where I'm trying in infinite loop.
PHP:
<?php
while(1)
{
$get_stream_data = fopen('https://api.xyz.com:8100/update-stream/connect', 'r');
if($get_stream_data)
{
$stream_data = stream_get_contents($get_stream_data);
$save_stream_data = getStreamingData($stream_data);
if($save_stream_data == true)
{
continue;
}
}
else
{
sleep(1);
continue;
}
}
function getStreamingData($stream_data)
{
$to = "accd#xyz.com";
$subject = "Stream Details";
$msg = "Stream Details : ".$stream_data;
$headers = "From:streamdetail#xyz.com";
$mailsent = mail($to,$subject,$msg,$headers);
if($mailsent){
return true;
}else {
return false;
}
}
?>
Error:
Warning: fopen(https://api.xyz.com:8100/update-stream/connect): failed to open stream: Connection timed out in /home/public_html/get_stream_data/index.php on line 4
I couldn't get the data by my end while it is giving an updates by the server in live.
I checked that live streaming in a command prompt using below command.
CURL
curl --get 'https://api.xyz.com:8100/update-stream/connect' --verbose
First, this is best done with PHP's curl functions. See the various answers to PHP file_get_contents() returns "failed to open stream: HTTP request failed!"
If you stick with fopen() you probably need to set up the context for SSL, and it may involve installing some certificates. See file_get_contents(): SSL operation failed with code 1. And more (and note the security warning about the accepted answer)
Finally, your while(1) loop is around the fopen() (which is okay for re-starts after relatively rare failures), but you actually want it inside. Here is your code with just the minimal changes to show that:
<?php
while(1)
{
$get_stream_data = fopen('https://api.xyz.com:8100/update-stream/connect', 'r');
if($get_stream_data)while(1)
{
$stream_data = stream_get_contents($get_stream_data);
$save_stream_data = getStreamingData($stream_data);
if($save_stream_data == true)
{
continue;
}
sleep(1);
}
else
{
sleep(1);
continue;
}
}
UPDATE: The above code still nags at me: I think you want me to using fread() instead of stream_get_contents(), and use blocking instead of the sleep(1) (in the inner loop).
BTW, I'd suggest changing the outer-loop sleep(1) to be sleep(3) or sleep(5) which are typical defaults in Chrome/Firefox/etc. (Really, you should be looking for the SSE server sending a "retry" header, and using that number as the sleep.)
I have been trying to make a PHP socket server, something I never done before. So I might not get how all the socket_* functions work.
What I have trouble with is the timeout function in socket_select.
while(true){
//Copy $clients so the list doesn't get modified by socket_select();
$read = $clients;
$write = $clients;
//new socket tries to connect
if(!$new = socket_accept($socket)){
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error()); break;
}
//Accept the new client
if(!in_array($new, $clients)){
$clients[] = $new;
sendMessage($new, "Hello and welcome to the PHP server!");
}
//Wait for read
socket_select($read, $write, $empty, 5, 5);
foreach($read as $client){
$id = array_search($client,$clients);
echo $id." ".readMessage($client);
}
//Write data to the connected sockets
foreach($write as $client){
sendMessage($client, rand(0,99999));
}
echo "I'm bored\n";
}
From what I understand of socket_select is that this script should say, "I'm bored" every 5 seconds. But it doesn't, why?
Why I want to timeout socket_select is to make a loop so I can send data to the connected sockets.
You're calling socket_accept() every time around the loop. This call will block if no new connections have arrived.
Add $socket to the array of sockets you pass to socket_select(), and only call socket_accept() if that socket shows up as readable. (You'll also need to make that socket an exception in your other loops so that you don't try to write to it.)
I want to create an easy PHP server (TCP-based) that would serve actual time and close the connection immediately. I've done that already. I wanted to add crtl-C handling so I needed to replace blocking socket_accept with non-blocking (this is because when the blocking socket_accept instruction is reached and I send SIGINT /ctrl-C/ then the server will still be alive until the first client is server and then it closes itself - and I didn't want this behavior).
My current code looks like this:
<?php
error_reporting(E_ALL);
ob_implicit_flush();
if ($argc != 2)
die("Wrong params");
$address = 'localhost';
$port = $argv[1];
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false)
die(socket_strerror(socket_last_error()) . "\n");
if (socket_bind($sock, $address, $port) === false)
die(socket_strerror(socket_last_error($sock)) . "\n");
if (socket_listen($sock, 5) === false)
die(socket_strerror(socket_last_error($sock)) . "\n");
socket_set_nonblock($sock);
$remote_host = $remote_port = $msgsock = null;
declare(ticks = 1);
function sig_handler($signo)
{
switch ($signo) {
case SIGTERM:
case SIGINT:
global $sock;
socket_shutdown($sock);
socket_close($sock);
echo "Terminating...\n";
exit;
}
}
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGINT, "sig_handler");
echo "Starting server\n";
while (1) {
do {
$msgsock = socket_accept($sock);
usleep(100000);
} while ($msgsock === false);
socket_getpeername($msgsock, $remote_host, $remote_port);
echo "Connection made from {$remote_host}:{$remote_port}\n";
$msg = date('r', time()) . "\n";
socket_write($msgsock, $msg, strlen($msg));
socket_close($msgsock);
};
socket_close($sock);
Everything works fine except for one detail... I get the following PHP warning every 0.1 second (= 100000 microseconds):
PHP Warning: socket_accept(): unable to accept incoming connection [11]: Resource temporarily unavailable in /home/tomasz/Development/Python/twisted/time-server.php on line 55
PHP Stack trace:
PHP 1. {main}() /home/tomasz/Development/Python/twisted/time-server.php:0
PHP 2. socket_accept() /home/tomasz/Development/Python/twisted/time-server.php:55
What I've tried to achieve is non-blocking accept: PHP uses the server socket, checks if there's any connection awaiting to be served. I not - wait 0.1 second. If there is a pending connection, serve it. All functionality is OK except that I've got no idea why is this warning thrown - I just want to check if there's any connection to be served. Modifying error_reporting to E_ERROR makes the warnings quiet, but I hope there's a better way to solve that...
edit:
modifying socket_accept($sock) to #socket_accept($sock) will just suspress warnings from being thrown, but still this doesn't state why it is thrown...
I located your question while searching for a solution to the exact same problem. Additionally, I found a few other posts asking about the same thing, but also without solutions. Some posts indicated that there was no way to prevent socket_accept() from throwing warnings, as it is by design to indicate "there is no waiting connection to accept." I couldn't confirm this as it doesn't seem to be mentioned in the PHP manual page for socket_accept()
Like you, I wasn't satisfied with using any sort of error suppression. It seemed the next logical step was to wrap socket_accept() in some sort of conditional so that it would only execute if I knew there was a connection waiting. I couldn't find anything that did this. But when using stream_*() functions instead of just socket_*() functions, it looks like there is. So I switched out to using streams (seems there are some other advantages as well), as follows:
if (( $socket = stream_socket_server( "tcp://$address:$port", $errno, $errstr )) === FALSE ) {
die( "failed to create socket: $errstr\n" );
}
echo "Waiting for clients to connect...\n";
while ( $server_listening ) {
$read = array( $socket );
$array = array();
if ( stream_select( $read, $array, $array, 0 )) {
$connection = stream_socket_accept( $socket, 0 );
client_handler( $socket, $connection );
} else {
usleep( 100 );
}
}
This seems to work well. My script only attempts to accept the connection if it first determines that there is a connection waiting. After going through this, I did find that there was an equivalent socket function for this, socket_select(), which appears to work the same way. So you may be able to do something similar if you wanted to stick with the socket_*() functions.
On a side note, I'm glad I made the switch to streams as they seem easier to work with. And since my application is limited to TCP, I don't seem to be missing any functionality that I would get with more low-level sockets.
There is something that does that, and it's select(). Nonblocking socket IO should use select(), period. In PHP that means socket_select(). See any reference on BSD sockets for more info.
I've written a database application using MySQL and PHP on the server side, and Flex on the client side. I use a php socket to have it automatically update all clients whenever changes are made to the database.
The whole system works swimmingly, but every now and then the socket seems to stop responding. The strange thing is that the connection is still good – any changes a client performs are implemented, but the socket doesn't broadcast the message. The socket file isn't throwing any errors (though when I run error_log from the socket those messages appear). Memory use of the socket doesn't change on the server, and no disconnect signal is sent. Stranger still, eventually the socket starts working again, after about half an hour or so. If I restart the socket that also solves the problem.
I'm working on a hacky solution allowing the client to restart the socket if it becomes unresponsive, but that's unsatisfying and open to mistakes. What I'd really like is to learn why this might be happening. Does the socket somehow get "saturated" after a certain number of connections? Should I be doing something to clean up the socket server? I've tried three different physical servers (one local and two online) and the same thing happens, so it's definitely me.
I feel like there's something basic that I'm doing wrong. Here's the code I'm using for the socket server (it's a slightly modified version of socket written by Raymond Fain on kirupa.com, so I've left his original comment at the top):
#!/usr/bin/php -q
<?php
/*
Raymond Fain
Used for PHP5 Sockets with Flash 8 Tutorial for Kirupa.com
For any questions or concerns, email me at ray#obi-graphics.com
or simply visit the site, www.php.net, to see if you can find an answer.
*/
//ini_set('display_errors',1);
//ini_set('display_startup_errors',1);
error_reporting(E_ALL);
ini_set('error_log', 'socket_errors.log');
ini_set('log_errors', 'On');
ini_set('display_errors', 'Off');
set_time_limit(0);
ob_implicit_flush();
error_log('testing');
$address = 'xxx.xxx.xx.xx';
$port = xxxxx;
function send_Message($allclient, $socket, $buf)
{
$buf = str_replace("\0","",$buf);
//echo "<mbFeed>$buf</mbFeed>\n\0";
foreach($allclient as $client)
{
socket_write($client, "<mbFeed>$buf</mbFeed>\n\0");
}
}
echo "connecting...
";
//---- Start Socket creation for PHP 5 Socket Server -------------------------------------
if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0)
{
echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}
socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);
if (($ret = socket_bind($master, $address, $port)) < 0)
{
echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}
echo 'socket bind successfull.
';
if (($ret = socket_listen($master, 5)) < 0)
{
echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
$read_sockets = array($master);
echo "connected.";
//---- Create Persistent Loop to continuously handle incoming socket messages ---------------------
while (true)
{
$changed_sockets = $read_sockets;
$num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);
foreach($changed_sockets as $key => $socket)
{
if ($socket == $master)
{
if (($client = socket_accept($master)) < 0)
{
echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
continue;
}
else
{
array_push($read_sockets, $client);
}
}
else
{
$bytes = socket_recv($socket, $buffer, 8192, 0);
if ($bytes == 0)
{
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
}
else
{
$allclients = $read_sockets;
array_shift($allclients);
//any messages starting with ::: are not to be broadcast, and may be used for other things. This message
//usually comes from the client.
if (substr($buffer, 0, 3) == ":::") handleSpecial(substr($buffer, 3));
else
{
//otherwise the message comes from a php file that will be closed, so the socket needs to be closed.
unset($read_sockets[$key]);
unset($changed_sockets[$key]);
socket_close($socket);
send_Message($allclients, $socket, $buffer);
}
}
}
}
}
function handleSpecial($message)
{
error_log($message);
}
?>
As the sockets in use seem to be blocking the call to socket_recv() might not return until the amount of data requested was read. And with this does not handle any other reading sockets, including the accecpting socket.
To get around this use socket_set_nonblock() to make the sockets unblocking. Please note that a call to socket_recv() on a non-blocking socket might return having read less bytes than requested, and therefore the amount of data read shall be tracked for each socket.
Here is the code that I am using:
if (!($fp = fsockopen('ssl://imap.gmail.com', '993', $errno, $errstr, 15)))
echo "Could not connect to host";
$server_response = fread($fp, 256);
echo $server_response;
fwrite($fp, "C01 CAPABILITY"."\r\n");
while (!feof($fp)) {
echo fgets($fp, 256);
}
I get the first response:
OK Gimap ready for requests from xx.xx.xx.xx v3if9968808ibd.15
but then the page times out. I have searched through stream_set_blocking, stream_set_timeout, stream_select, fread, etc. but could not get it to work. I need to read all the data that the server sends and then proceed with other commands (I would be retrieving emails using imap).
Thanks
Your script is hanging in the while loop at the end. This is because you have used !feof() as the condition for the loop, and the server is not closing the connection. This means the feof() will always return false and the loop will continue forever.
This will not be problem when your write a full implementation, as you will be looking for response codes and can break out of the loop accordingly, for example:
<?php
// Open a socket
if (!($fp = fsockopen('ssl://imap.gmail.com', 993, $errno, $errstr, 15))) {
die("Could not connect to host");
}
// Set timout to 1 second
if (!stream_set_timeout($fp, 1)) die("Could not set timeout");
// Fetch first line of response and echo it
echo fgets($fp);
// Send data to server
echo "Writing data...";
fwrite($fp, "C01 CAPABILITY\r\n");
echo " Done\r\n";
// Keep fetching lines until response code is correct
while ($line = fgets($fp)) {
echo $line;
$line = preg_split('/\s+/', $line, 0, PREG_SPLIT_NO_EMPTY);
$code = $line[0];
if (strtoupper($code) == 'C01') {
break;
}
}
echo "I've finished!";
Your script should be working. In fact, it is working.
See the results below on my pc when I ran your code:
* OK Gimap ready for requests from xx.xx.xx.xx l5if4585958ebb.20
* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH
C01 OK Thats all she wrote! l5if4585958ebb.20
Since gmail doesn't disconnect you. No end of file occurs. And the page loading simply times out.
In other words: Your script will just keep waiting and waiting until gmail does disconnect, which unfortunately happens after your page load has already timed out.