⬆️ ⬇️

Websockets. Possible approach to use

Colleagues, welcome. I want to bring to the public discussion my thoughts and some moments of the implementation of my project. Websockets - the topic is probably already beaten, but I was stimulated by the work of the “WebRTC Cookbook” by Andrii Sergiienko, in which the Websockets technology is used as a signaling service for managing streaming data.



In its pure form, the Websockets protocol does not contain anything that could multiplex data. Many clients from different projects can connect to the Websockets service at the same time. So I would like to have a fully utilized approach for different platforms, services, websites, etc.



The above book is accompanied by examples. One of them is the implementation of Java Websockets service, where data multiplexing occurs by the number of the chat room. The room number (or name) is assigned by the application programmer. I would not like to immediately indicate this as a definite shortcoming. All the same, this is an educational project. Let me just say that for my project I put the following requirements:





Questions about data encryption and reliability of such a service, perhaps you can not raise. All the same, this is a bit of a different subject area.

')

So, what is offered and what is implemented? The following figure suggests the following service layout:



image



In the figure, the numbers indicate the following interaction participants:



  1. Various sources of events in the network.
  2. HTTP server, where these events from the sources are received, accumulated, processed.
  3. Websockets service, used for online notification of information consumers. In addition to this service itself, there should be an integration with “its own” HTTP-server transmitting structured information from various projects.
  4. These are actually clients, which are receivers of processed information from various sources 1.


In order to somehow organize the data for messaging with the service, it is proposed to select the JSON format. This choice is due to the simplicity of working with JSON strings, a wide range of different libraries and their portability for different platforms.



{ "WSCI_TYPE" : "WSCI_REG", "WSCI_ID" : "bqOPfKmKCPV … zJS2LqtFang" } 


WSCI_TYPE - type of the received message. In this case, WSCI_REG means that it is a registration message, in which the identifier or token of the connection is passed through the WSCI_ID parameter. With this key, the application is “shared” with other users of the service. The key can be recorded in the database or in some lists with shared access and other users of various services. I note that a similar principle of operation was borrowed from Google. They have a GCM ( Google Clouds Messaging ) service.



The next message type is WSCI_DATA. It actually transmits user data. It looks like this:



 { "WSCI_TYPE" : "WSCI_DATA", "WSCI_DATA" : “   ” } 


Between the user server (2) and the WebSockets service (3), another message type is transmitted, the format of which is as follows:



 { "WSCI_ARRAY" : [  ( )], "WSCI_DATA" : " " } 


For example:



 { “WSCI_ARRAY”:[“d97I.....r2Oo”, “o7yz....tIu7”], “WSCI_DATA”:”This is your data” } 


The WSCI_ARRAY array contains a list of connection identifiers (tokens). On PHP, the formation of such a message is as follows:



 $testJSON = array( 'WSCI_ARRAY'=>array( "d97I....r2Oo", "o7yz....MtIu7" ), WSCI_DATA'=>'This is a data for service.' ); 


To transfer data from the site to the Websockets service, you can use the class represented by the following listing:



 define('WSCI_SERVICE', "http://95.47.161.69/wsci.php"); class WsciCurl { function __construct(){} function __destruct(){} // function SendDataToWSCI($wsci_array, $wsci_data){ $data = base64_encode( json_encode( array( "WSCI_ARRAY"=>$wsci_array, "WSCI_DATA"=>$wsci_data ) ) ); $fields = array('data'=>$data); // $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, WSCI_SERVICE); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); $response = curl_exec($ch); curl_close($ch); $json_answer = json_decode($response); return $json_answer->{'result'}==='success'; } };  1.        Websockets. 


The following piece of text demonstrates the transfer of user data to the service.



 require_once('wsci_curl.php'); $wsci_array = array( "d97ICUblJKsOBH2YmWJqf0WU8Z9IaMemutFNLH8adFuFkXKmAe0ze3zlptSr2Oo", "o7yzZjIp1tcoaREUBG8h4XObLTbTykMk2zSFSJ2TFEA5qV0a4Vt1g0Hno3MtIu7" ); $wsci_data = 'This is a data for service.'; $wsci = new WsciCurl(); $wsci->SendDataToWSCI($wsci_array, $wsci_data); 


In the $ wsci_array array, the tokens of the connections to which data should be sent are placed.



As an example of an event handler on the client side (4), we can offer the following JavaScript code fragment:



 var wsUrl = "ws://95.47.161.69:12080"; // var ws = new WebSocket(wsUrl); ws.onopen = function(evt){ onOpen(evt) }; ws.onclose = function(evt){ onClose(evt) }; ws.onmessage = function(evt){ onMessage(evt) }; ws.onerror = function(evt){ onError(evt) }; .... ws.close(); .... function onOpen(evt){ alert("Connected!"); } function onClose(evt){ alert('Finishing code: ' + evt.code); } function onMessage(evt){ var jsonObj = JSON.parse(evt.data); var type = jsonObj.WSCI_TYPE; switch( type ) { case "WSCI_REG" : { var id = jsonObj.WSCI_ID; alert('Key = ' + id); //   , ,   break; } case "WSCI_DATA" : { var data = jsonObj.WSCI_DATA; alert('Data: ' + data); //        break; } } } function onError(evt){ alert('Error: '+evt.data); }  2.      . 


Now consider the node (3) and analyze what is happening here. If you pay attention to Listing 1, you can see that the wsci.php module is the entry point to this service and is designed to receive user data (for clarification, it is accepted via the HTTP protocol) and translate it to the Websockets service. The module text is as follows:



 <?php define('WSCI_SERVER', "127.0.0.1"); define('WSCI_PORT', 12080); require_once('wsci_client.php'); ini_set('display_errors', 1); error_reporting(E_ALL); //  POST- $data = $_POST["data"]; if ( empty($data) || strlen($data)==0 ) { //There are no data for service $responce = array('result'=>'fail'); echo json_encode($responce); exit(0); } $data = base64_decode($data); //    //   $wsci = new WsciClient(); $bc = false; //     Websockets for($i=0; $i<10; $i++, usleep(200000)) if ( ($bc = $wsci->connect(WSCI_SERVER, WSCI_PORT, "/"))==true ) break; //   if ( !$bc ) { //Connection to websocket service is fail $responce = array('result'=>'fail'); echo json_encode($responce); exit(0); } //    $wsci->sendText($data); //  $wsci->sendClose(); $wsci->disconnect(); // //  echo json_encode(array("result"=>"success")); ?> 


Listing 3. Module of user data translation to web service



Consider what and how should happen in the service Websockets. First, it is necessary to determine the protocol of interaction with customers. I may be mistaken, but now the well-established standard is RFC_6455. Secondly, in the minimum level of service functionality. It appears (and it is implemented) that the service should perform the following set of functions:





Direct implementation of the service



Development and debugging was preceded by the work of finding and analyzing ready-made solutions and the possibilities of using them for their own purposes. There were absolutely exotic versions of implementations, for example, in JavaScript. A good case was the PHP implementation in which echo control was programmed. There are many ready-made, good examples in Java. There is a version of the Websockets module that integrates into Apache. But since we are not looking for simple ways, the option of developing in C ++ was chosen. It is difficult, troublesome, to debug, but nevertheless this option was chosen for the following reasons:





Some issues and difficulties in implementation



When designing applications, one always has to take into account the realities of being, lay down on the limitations of the environment, equipment performance, operating system capabilities, communication channel bandwidth, etc. So, I would like to hear your opinion, dear colleagues, about the maximum number of connections, taking into account hosting on VDS. Currently, the service load is minimal, 100 positions are allocated for the array of connections. Will the service work successfully with, say, 10,000 connections? Does anyone have this experience?



Now the size of the key (token) connection. As far as I remember, Google has a token length in the GCM service of 256 bytes. The question is, how justified is this? Isn't such a long key redundant? The fact is that with a large number of connections, the search for a specific connection by key can take a long time. Again, sort these objects by key. Just in case, I note that in my case the key size is 64 bytes.



One more of the points that could be added to the list of requirements for the service, I would refer the implementation of the application as a daemon, and setting it to autoload the operating system. This increases the overall reliability of the service and allows you to identify bottlenecks during subsequent operation.



Perspectives



You can make a “cloud”. Of course, in economic terms, competing with the “monsters” of the IT industry is not realistic. Just considering the possibility of implementation in principle.



Implementation examples



Here is an example and description of a simple use of the service.

And this is a video chat prototype .

There is also an implementation option for Android.

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



All Articles