📜 ⬆️ ⬇️

Web sockets for php. Choosing a web server server

A long time ago I published an article on Habré how to write my web server server from scratch . The article has grown into a library . For several months I have been engaged in its development, for several more years - support and bug fixes. Wrote the integration module with yii2. Some enthusiast wrote integration with laravel. My library is compatible with php7. Recently, I decided to abandon its further support (reasons below), so I want to help its users switch to another library.



Before I started writing my web server, I chose from finished products, and at that time there were only two: phpdaemon and ratchet.

phpdaemon


1400 stars on githaba
')

Ratchet


3600 stars on githaba


These libraries were very monstrous and at the same time did not meet my internal requirements:


I needed the timers to write games on the web socket to calculate interactions between all users every 0.05 seconds.

In the end, I wrote a library for myself and shared it with the community on the githaba . He made several demos (including the game "tanchiki"). Rewrote the third-party game (with the permission of the authors) from node.js to my library. Did load testing. Demos worked for years without rebooting. Tried to answer tickets during the day. All of this showed that my library could be used in production and many people used it.

There was only one problem. I had enough of my library to use in my projects, but others did not. They wanted me to develop it, but I did not need it. Someone needed windows support, and someone needed ssl, pg_notify, safari, pthreads, and more. Open tickets with requests for the implementation of various functionalities hang over the years.

Not so long ago, I decided to reconsider again what products might be useful for users of my library and was pleasantly surprised that besides the two projects described above, a third one appeared. He completely satisfied my needs and even more.

Workerman


4500 stars on githaba


His first release was two years ago, but for some reason more and more new people began to use my library for new projects. I can still understand that they use it on old projects (it works - do not touch it), but on new ones ... - for me it was a mystery.

If you google php websocket, then the first page is my article on Habré, and the second is Ratchet, which may seem complicated to someone and he will choose my library because of this or refuse to do web-based solutions altogether.

Well, the time has come to correct this annoying mistake and convey to as many people as possible about the existence of such a library as Workerman and give some examples on its use.

There are already a few examples on the githaba project main page. Consider one of them:

websocket server
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // Create a Websocket server $ws_worker = new Worker("websocket://0.0.0.0:8000"); // 4 processes $ws_worker->count = 4; // Emitted when new connection come $ws_worker->onConnect = function($connection) { echo "New connection\n"; }; // Emitted when data received $ws_worker->onMessage = function($connection, $data) { // Send hello $data $connection->send('hello ' . $data); }; // Emitted when connection closed $ws_worker->onClose = function($connection) { echo "Connection closed\n"; }; // Run worker Worker::runAll(); 
tcp server
 <?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // #### create socket and listen 1234 port #### $tcp_worker = new Worker("tcp://0.0.0.0:1234"); // 4 processes $tcp_worker->count = 4; // Emitted when new connection come $tcp_worker->onConnect = function($connection) { echo "New Connection\n"; }; // Emitted when data received $tcp_worker->onMessage = function($connection, $data) { // send data to client $connection->send("hello $data \n"); }; // Emitted when new connection come $tcp_worker->onClose = function($connection) { echo "Connection closed\n"; }; Worker::runAll(); 

To run the example, you need to install workerwan: composer require workerman/workerman
An example can be run using the php test.php start command and in the console we will see:
----------------------- WORKERMAN -----------------------------
Workerman version:3.3.6 PHP version:7.0.15-0ubuntu0.16.10.4
------------------------ WORKERS -------------------------------
user worker listen processes status
morozovsk none websocket://0.0.0.0:8000 1 [OK]
----------------------------------------------------------------
All workerman commands:
php test.php start
php test.php start -d - to demonize the script
php test.php status
php test.php stop
php test.php restart
php test.php restart -d
php test.php reload

In principle, using the first example, you can make a chat on webboxes and other examples are not needed. But over the course of several years, I realized that basically the users of my library needed an example of how to send a notification from their code to php to a selected user, and not to everyone at the same time, as often happens in examples.

For example:


From the two examples above you can put together one that will do what we need:

Sending a message to one user:
server.php server code:

 <?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; //          $users = []; //  ws-,        $ws_worker = new Worker("websocket://0.0.0.0:8000"); //  ,      ws- $ws_worker->onWorkerStart = function() use (&$users) { //   tcp-,          $inner_tcp_worker = new Worker("tcp://127.0.0.1:1234"); //   ,   , //    tcp-   $inner_tcp_worker->onMessage = function($connection, $data) use (&$users) { $data = json_decode($data); //     userId if (isset($users[$data->user])) { $webconnection = $users[$data->user]; $webconnection->send($data->message); } }; $inner_tcp_worker->listen(); }; $ws_worker->onConnect = function($connection) use (&$users) { $connection->onWebSocketConnect = function($connection) use (&$users) { //      get-,         $users[$_GET['user']] = $connection; //  get-      cookie,  $_COOKIE['PHPSESSID'] }; }; $ws_worker->onClose = function($connection) use(&$users) { //      $user = array_search($connection, $users); unset($users[$user]); }; // Run worker Worker::runAll(); 

client code client.html:

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <script> ws = new WebSocket("ws://127.0.0.1:8000/?user=tester01"); ws.onmessage = function(evt) {alert(evt.data);}; </script> </head> </html> 

code to send messages from our site send.php:

 <?php $localsocket = 'tcp://127.0.0.1:1234'; $user = 'tester01'; $message = 'test'; //    tcp- $instance = stream_socket_client($localsocket); //   fwrite($instance, json_encode(['user' => $user, 'message' => $message]) . "\n"); 

For the sake of fairness, I decided to write the same example for ratchet, but the documentation did not help me, like 3 years ago. But on stackoverflow, they offered a bit of a crutch, but a working version: connect from your php script via a ws connection. Of course, this is not as easy as connecting to a tcp socket using stream_socket_client and sending a message using fwrite. But already something.

Plus, there is still an unanswered question for me: does ratchet support the ability to run multiple workers and, if so, how to send a message to one user in this case, because it’s not clear what worker he is at. At workerman it can be done like this .

In general, I chose the Workerman library for myself and recommend that users of my library switch to it. All the examples are on the githaba .

Update: recommend swoole in the comments. I came across this library earlier, but I got the false impression that it does not support php7 and after that it fell out of my circle of vision. And in vain. Interesting library.

Source: https://habr.com/ru/post/331462/


All Articles