i was saving the stdout in read_sock instead of read_socks array, now its resolved
Can't monitor STDOUT of a C program in parallel with web sockets, by using stream select in PHP
-
15-07-2023 - |
質問
I m writing a websocket based client server in PHP.Server is listeninig for clients which get connected from a browser, when client write something its echoed back to the client. Client input and new connection from the client are monitored by using stream select. In my previous work I used stream select to get output of the C program and display it on the browser now I want that when a client send some message I execute a C program using proc open. C program outputs "hello" message in a loop after certain time, I want that when ever there is output on the C program I send it to the client browser.
Client browser successful gets connected, when client sends data the server echo it back, the C program gets executed on server but I cant monitor its STDOUT by using same stream select that is monitoring my sockets.
I am not able to monitor my child process STDOUT using stream select. By using select How can I monitor the new process STDOUT that I started using proc open ,It looks that some how I lost the STDOUT descriptor that is usually accessible after starting the C program by using proc open.
hello.c
#include<stdio.h>
#include<stdint.h>
void main(void)
{
uint8_t i = 0;
uint8_t count = 10;
for(i = 0; i < count; i++)
{
printf("hello world\n");
sleep(1);
}
}
server.php
execute_prog('unbuffer /var/www/html/test/./hello3');//unbuffer stdout
function execute_prog($exe)
{
echo "[+execute_prog]";
$host = 'localhost'; //host
$port = '9000'; //port
$null = NULL; //null var
$read_socks;
$new_client;
$server = stream_socket_server("tcp://0.0.0.0:9000", $errno, $errorMessage);
if ($server === false)
{
throw new UnexpectedValueException("Could not bind to socket: $errorMessage");
}
set_time_limit(1800);
$exe_command = escapeshellcmd($exe);
$descriptorspec = array(
0 => array("pipe", "r"), // stdin -> for execution
1 => array("pipe", "w"), // stdout -> for execution
2 => array("pipe", "w") // stderr
);
{
$client_socks = array();
$read_socks = array($server);
$changed = array();
$stdout = NULL;
while(1)
{
//prepare readable sockets
$write = NULL;
$err = NULL;
$except = NULL;
$changed = $read_socks;//by refrence
if (false === ($num_changed_streams = stream_select($changed, $write, $except, 0)))
{
/* Error handling */
echo "Errors\n";
}
else if ($num_changed_streams > 0)
{
/* At least on one of the streams something interesting happened */
echo "Data on ".$num_changed_streams." descriptor\n";
if(in_array($stdout[0], $changed))
{
echo "Data on child process STDOUT\n";
$s = fgets($stdout[0]);
if( $s === false )
{
// Hello program has finished.
echo 'Finished', PHP_EOL;
$s = NULL;
ob_flush();
flush();
// Close all descriptors and return...
// break;
}
else
{
echo $s."</br>";
//fwrite($new_client,$s,strlen($s));//commented temporarily
$s = NULL;
ob_flush();
flush();
}
}
else if(in_array($server, $changed))
{
//new client
echo "New Connection\n";
$new_client = stream_socket_accept($server);
if ($new_client)
{
//print remote client information, ip and port number
echo 'Connection accepted from ' . stream_socket_get_name($new_client, true) . "n";
$read_socks[] = $new_client;
echo "Now there are total ". count($read_socks) . " clients.n";
}
$header = fread($new_client, 1024);//read data sent by the socket
perform_handshaking($header, $new_client, $host, $port); //perform websocket handshake
$ip = stream_socket_get_name($new_client, true);
$response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data
fwrite($new_client,$response,strlen($response));
//delete the server socket from the read sockets
unset($changed[ array_search($server, $changed) ]);
}
else if($write)
{
echo "Data on child process STDIN\n";
}
else if($err)
{
echo "Data on child process STDERR\n";
}
else
{
echo "Message from the client \n";
//message from existing client
foreach($changed as $sock)
{
$data = fread($sock, 128);
//echo "Data read:".$data." From sock:".$sock."\n";
if(!$data)
{
unset($client_socks[ array_search($sock, $client_socks) ]);
@fclose($sock);
echo "A client disconnected. Now there are total ". count($client_socks) . " clients.n";
continue;
}
else
{
$received_text = unmask($data); //unmask data
$tst_msg = json_decode($received_text); //json decode
$user_name = $tst_msg->name; //sender name
$user_message = $tst_msg->message; //message text
$user_color = $tst_msg->color; //color
// echo "name:".$user_name." user mesg:".$user_message."\n";
//prepare data to be sent to client
$response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color)));
fwrite($sock, $response_text, strlen($response_text));
//..................................................................................................................
echo "Executing a process\n";
$process = proc_open($exe_command, $descriptorspec, $pipes);//creating child process
if (is_resource($process))
{
echo "Process Created";
}
$read_sock[] = $pipes[1];//add a descriptor
$stdout = array($pipes[1]);//save stdout in a variable defined above
print_r ($stdout);
}
}
}
$num_changed_streams = 0;
}
}
// close the listening socket
fclose($server);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
echo "exitcode: ".proc_close($process)."\n";
}
echo "[-execute_prog]";
// return $ret;
}
Output Of server.php
[+execute_prog]Data on 1 descriptor
New Connection
Connection accepted from 127.0.0.1:49875nNow there are total 2 clients.nData on 1 descriptor
Message from the client
Executing a process
Process Created Array
(
[0] => Resource id #12
)
As can be seen from output that it never show message "Data on child process STDOUT" even the C program was created
Other utility functions unmask, mask etc can be provided if required.
Thankyou
解決