NotionCommotion Posted January 6, 2017 Share Posted January 6, 2017 A remote client has connected to the following server described at the bottom of this page, has told the server that its GUID is 123456789, and the server has created a map between this GUID and the specific client connection.Another script index.php is ran through Apache on the same machine as the sockets server. <?php $guid=123456789; $data='{"message":"hello"}'; someFunctionToSendDataToSocketsServer($guid,$data); Somehow, I would like to have index.php send $guid=123456789 and $data='{"message":"hello"}' to the sockets server, and then execute: $client=$this->findConnectionByGuid($guid); $client->write($data); someFunctionToSendDataToSocketsServer() should be a blocking function up to the sockets server writing the data (but not that the client received it and acknowledged it) and should return true/false (or a 200/400 header, or some other means to indicate status). At first, I was thinking of using a ReactPHP HTTP server operated on the same loop as the sockets server. index.php would then use curl to send it to the HTTP server, the HTTP server on request event would get the data, and if valid format send the data to the client and return a 200 header, and if not valid format, return a 400 header. ReactPHP, however, says that the HTTP server is not stable. Another option would be to add a sockets client to the server machine and have index.php use that client to send the data to the sockets server. I don’t think this make sense, however, as index.php is not communicating bi-directional with the sockets server. Also, it adds a little complication as the sockets server is currently designed to receive connections from remote clients which send the server their unique GUID. Lastly, from a security standpoint, I don’t want the remote clients to somehow gain privileges available to only index.php. Or maybe a redis queue where index.php places the content in the queue, and it pops out in the server script where it is sent. I am not sure how the true/false status would work. Or maybe something else altogether? Any advice? <?php namespace MyServer; use React\EventLoop\Factory; use React\Socket\Server as SocketServer; use SplObjectStorage; require 'JSONStream.php'; class Server { private $app, //The main application $url_sockets, //Host and port for the socket $clientList; //SplObjectStorage public function __construct($url_sockets,$app) { $this->app = $app; $this->url_sockets=$url_sockets; $this->clientList = new SplObjectStorage(); } public function start() { $loop = Factory::create(); $socket = new SocketServer($loop); $socket->on('connection', function (\React\Socket\ConnectionInterface $client){ $client = new \Kicken\RLGL\JSONStream($client); $this->clientList->attach($client, []); $client->on('data', function($data) use ($client){ // The server doesn't know the client's GUID until the client sends this data to the server if($guid=$this->getConnectionID($client)) { $this->app->process($data, $guid, $client); } elseif($guid=$this->app->getGUID($data)) { $this->addConnection($client, $guid); } }); $client->on('close', function($conn) use ($client) { if($this->socketClients->contains($client)) { $this->socketClients->detach($client); } }); $client->on('error', function($conn) use ($client) { $client->close(); }); echo "New connection accepted.\r\n"; }); $socket->listen($this->url_sockets['port'],$this->url_sockets['host']); $loop->run(); } private function addConnection($client, $guid) { $this->clientList[$client]['guid']=$guid; } private function getConnectionID($client) { return $this->clientList[$client]['guid']; } private function findConnectionByGuid($guid) { //There should be a better way to do this??? $this->socketClients->rewind(); while($this->socketClients->valid()) { if($guid == $this->socketClients->getInfo()) { return $this->socketClients->current(); } $this->socketClients->next(); } return false; } } Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/ Share on other sites More sharing options...
requinix Posted January 7, 2017 Share Posted January 7, 2017 a) Have your code act as a client to the existing server and exchange data that way. b) Redis. Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541140 Share on other sites More sharing options...
Solution kicken Posted January 7, 2017 Solution Share Posted January 7, 2017 Your server and it's clients should communicate with some standard data layout. In my RLGL example for example every JSON structure contained a message field that indicated what type of data structure was being sent. You can use that field to then decide what to do with any data you receive. One of those actions could be something to forward data to a given client which is what your index.php script would use. $client->on('data', function($data) use ($client){ switch ($data['message']){ case 'register': $this->addConnection($client, $data['guid']); break; case 'forward': $forwardClient = $this->findConnectionByGuid($data['guid']); $forwardClient->send($data['data']); //Somehow determine success/failure and send the result //$client->send(['message'=> 'forward-result', 'success' => true]); break; default: $guid = $this->getConnectionID(); $this->app->process($data, $guid, $client); break; } }); Your index.php script can just use the react framework stuff to send your data and receive a response. Something like this: function sendToClient($guid, $forwardData){ $success = false; $loop = new \React\EventLoop\StreamSelectLoop(); $socket = new \React\SocketClient\TimeoutConnector(new \React\SocketClient\TcpConnector($loop), 15, $loop); $socket->create($server, $port)->then(function($stream){ $client = new \Kicken\RLGL\JSONStream($stream); $stream->on('data', function($data) use (&$success, $loop, $stream, $guid, $forwardData){ if ($data['message'] == 'forward-result'){ $success = $data['success']; $stream->close(); $loop->stop(); } }); $client->send([ 'message' => 'forward' , 'guid' => $guid , 'data' => $forwardData ]); }); //Generic timeout so this function doesn't block forever. $loop->addTimer(30, function() use ($loop){ $loop->stop(); }); $loop->run(); return $success; } 1 Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541141 Share on other sites More sharing options...
NotionCommotion Posted January 7, 2017 Author Share Posted January 7, 2017 b) Redis. Would server need a continuously loop which constantly checks if the queue has data in it? Your server and it's clients should communicate with some standard data layout. In my RLGL example for example every JSON structure contained a message field that indicated what type of data structure was being sent. You can use that field to then decide what to do with any data you receive. One of those actions could be something to forward data to a given client which is what your index.php script would use. ... Your index.php script can just use the react framework stuff to send your data and receive a response. Something like this: This seems to make sense, but to make sure I understand, I would like to explain it in my own words. Index.php creates a new client and connects to the server. It sends content with message of "forward", and waits for confirmation of message "forward-result". Upon confirmation or 30 seconds, it stops the loop. Will stopping the loop and/or the completion of the index.php script kill the connection to the server? Also, how would you recommend preventing one of the clients other than index.php which happens to know another's guid from forwarding something to that client? My thoughts are: Have index.php include a secret password which case 'forward': checks before forwarding. Have case 'forward': check that the client is on the same machine. I like option 2 more. Agree? Is it possible? Thanks Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541151 Share on other sites More sharing options...
requinix Posted January 7, 2017 Share Posted January 7, 2017 Would server need a continuously loop which constantly checks if the queue has data in it?Of sorts. Either it polls for changes in the main loop (if that's possible) or there's a separate PHP process running on the same machine that does blocking checks. But what kicken is describing (the "act as a client to the existing server" option) is better. If you want to lock down the ability to send messages to a client, so that client A can't force a message to client B, then you can always restrict the command to an IP range (ie, localhost and/or LAN). Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541152 Share on other sites More sharing options...
kicken Posted January 7, 2017 Share Posted January 7, 2017 Will stopping the loop and/or the completion of the index.php script kill the connection to the server?PHP will close the connection as part of it's shutdown process after the script ends. Just stopping the loop won't immediately close the connection but your script will probably be ending shortly after the loop is stopped so in effect it does. Also, how would you recommend preventing one of the clients other than index.php which happens to know another's guid from forwarding something to that client? Either of those would work fine. On the server you can get a client's remote address using ConnectionInterface::getRemoteAddress and compare that to 127.0.0.1 (or whatever). I'd probably go with some kind of authentication token that index.php has but the other clients don't. It's easy to do and will make it easier to split your server off to another machine in the future should you ever need too. Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541164 Share on other sites More sharing options...
NotionCommotion Posted January 8, 2017 Author Share Posted January 8, 2017 Thanks guys Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541165 Share on other sites More sharing options...
NotionCommotion Posted January 10, 2017 Author Share Posted January 10, 2017 I need to add use() to $socket->create and should probably remove some of the use() variables with $stream->on as shown below, right? function sendToClient($guid, $forwardData){ $success = false; $loop = new \React\EventLoop\StreamSelectLoop(); $socket = new \React\SocketClient\TimeoutConnector(new \React\SocketClient\TcpConnector($loop), 15, $loop); $socket->create($server, $port)->then(function($stream) use ($loop, $guid, $forwardData){ $client = new \Kicken\RLGL\JSONStream($stream); $stream->on('data', function($data) use (&$success, $loop, $stream){ if ($data['message'] == 'forward-result'){ $success = $data['success']; $stream->close(); $loop->stop(); } }); $client->send([ 'message' => 'forward' , 'guid' => $guid , 'data' => $forwardData ]); }); //Generic timeout so this function doesn't block forever. $loop->addTimer(30, function() use ($loop){ $loop->stop(); }); $loop->run(); return $success; } Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541256 Share on other sites More sharing options...
kicken Posted January 10, 2017 Share Posted January 10, 2017 Yea. You'll need to add &$success to the $socket->create level use statement also. Quote Link to comment https://forums.phpfreaks.com/topic/302885-how-to-get-content-into-a-reactphp-server/#findComment-1541259 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.