Closed ETMTrader closed 1 month ago
It depends on what you want to achieve.
If the code above is included on a php webpage, and you only want to output one or a few messages, you could just output it as you would with any php code.
But if you want to continuously update the page without reloading it, you probably want a javascript based client instead.
Thank you for reply.
I am getting currency prices and other data.
Right now I am running “php client.php start” in terminal and I am getting a lot of data every second.
So now i need to make a server? 1 - to be able to connect from another server and get data too 2 - to be able to get data in browser using javascript websocket
Where are you getting your quotes from? If it's an existing web-socket server, then you just need to use WebSocket JavaScript object to update the quotes on the web page in real time. Otherwise, you should build your own web-socket server first to broadcast quotes and connect to it from js script.
Yes, I'm connecting to an existing server. But I can only connect my websocket there.
I need to get data from one server and distribute this data to many clients.
Then you need both a websocket server and a websocket client. Your clients will connect to your server, and your websocket client will connect to a 3d party API server and every time it gets a new quote, this quote can be sent to all connected clients.
Thank for reply.
I don't understand how I can create a server and send onText messages there. I have a client.php file where I get the messages. How do I create a server and connect it all? Maybe there is an example somewhere?
I apologize if the questions are stupid)
OK. There is a VERY simple implementation for your case. Of cause, it doesn't fit for real production, just to give you a clue. client.php:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$client = new WebSocket\Client("wss://<3d-party-api-ws-server>");
$client
// Add standard middlewares
->addMiddleware(new WebSocket\Middleware\CloseHandler())
->addMiddleware(new WebSocket\Middleware\PingResponder())
// Listen to incoming Text messages
->onText(function (WebSocket\Client $client, WebSocket\Connection $connection, WebSocket\Message\Message $message) use ($redis) {
$redis->publish('test_channel', $message->getContent());
})
->start();
You get prices from your provider and send them to Redis, for example. Of cause, you can use other solutions: write to databases, files, queues, messages brokers of your choice. Now server.php
<?php
use Swoole\Coroutine as co;
use Swoole\WebSocket\Server;
//create async ws server
$server = new Server("127.0.0.1", 5000);
// When server starts
$server->on("Start", function ($server) {
// Start a new coroutine to subscribe to Redis channel
go(function () use ($server) {
$redis = new co\Redis();
$redis->connect('127.0.0.1', 6379);
$msg = $redis->subscribe(['test_channel']);
while ($msg = $redis->recv()) {
// Broadcast message to all clients
foreach ($server->connections as $fd) {
$server->push($fd, $msg[2]);
}
}
});
});
// When a client connects
$server->on('open', function ($server, $req) {
echo "Client {$req->fd} connected.\n";
});
// When a message is received
$server->on('message', function ($server, $frame) {
echo "Received message from {$frame->fd}: {$frame->data}\n";
});
// When a client disconnects
$server->on('close', function ($server, $fd) {
echo "Client {$fd} disconnected.\n";
});
// Start the server
echo 'Starting the server...' . PHP_EOL;
$server->start();
Here we use Swoole websocket server and redis client because they are async and better fit for your case. When we start the server, we subscribe to our Redis channel where our ws client sends quotes and on every quote we broadcast it to every connected frontend client. Simple example of web client:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Client</title>
</head>
<body>
<h1>WebSocket Client</h1>
<div id="messages"></div>
<script>
const socket = new WebSocket('ws://localhost:5000');
socket.onmessage = (event) => {
const messageDiv = document.getElementById('messages');
messageDiv.innerHTML += `<p>${event.data}</p>`;
};
socket.onopen = () => {
console.log('Connected to server');
};
socket.onclose = () => {
console.log('Disconnected from server');
};
</script>
</body>
</html>
I hope now you have a general idea how it should work.
This library includes both a client and a server, so you don't really need to use additional extensions.
Below is a very simple solution running in a single file. Downside is that it need to switch between client and server listeners, so there will be a short delay, as specified by $timeout
. It is tempting to set $timeout
to 0
, but don't - that will cause the script to use all available processing power even when doing nothing.
(You need to add some configuration, error handling, and initialization.)
<?php
require __DIR__ . '/vendor/autoload.php';
// Will switch context $timeout seconds or sooner
$timeout = 5;
$local_port = 80;
$local_ssl = false;
$remote_server_uri = "ws://remote_server";
// Setup server
$server = new WebSocket\Server($local_port, $local_ssl);
$server
->addMiddleware(new WebSocket\Middleware\CloseHandler())
->addMiddleware(new WebSocket\Middleware\PingResponder())
->setTimeout($timeout)
->onTick(function ($server) {
// We need to stop the listener to give client a chance to run
echo "Stop server \n";
$server->stop();
})
;
// Setup client
$client = new WebSocket\Client($remote_server_uri);
$client
->addMiddleware(new WebSocket\Middleware\CloseHandler())
->addMiddleware(new WebSocket\Middleware\PingResponder())
->setTimeout($timeout)
->onText(function ($client, $connection, $message) use ($server) {
// Broadcast received message to all connected clients
echo " -- Delegating {$message->getContent()} \n";
$server->send($message);
})
->onTick(function ($client) {
// We need to stop the listener to give server a chance to run
echo "Stop client \n";
$client->stop();
})
;
// Run loop
while (true) {
echo "Start server \n";
$server->start();
echo "Start client \n";
$client->start();
}
As @ev-gor is suggesting, you can also run client and server in two separate scripts using a shared storage as intermediate. A bit more complex but no delay using that strategy.
A queue based intermediate such as Redis or RabbitMQ would be the best solution, but you can also use a database, Memcached, or similar. These require 3d party services or extensions, so if you're running on a pre-configured server it might limit your options.
Hi I don't know much about websockets I have a question
I have created a websocket client and I get some data all the time.
How can I pass this data to the client web page?
I have seen the Client and Server solution but I don't understand how to do it.
I have a simple code