Keep a MQTT Client Connection always active - php

I am using CloudMQTT as a MQTT broker in my Pub-Sub based application. I am using my publisher to publish data to the CloudMQTT server over a topic, and I plan to subscribe to the broker on my webpage to recieve the transmitted information.
I am using this procedure to create a Client(subscriber): https://www.cloudmqtt.com/docs-php.html
Code goes as follows:
// subscribe.php
require("phpMQTT.php");
$host = "hostname";
$port = port;
$username = "username";
$password = "password";
$mqtt = new phpMQTT($host, $port, "ClientID".rand());
if(!$mqtt->connect(true,NULL,$username,$password)){
exit(1);
}
//currently subscribed topics
$topics['topic'] = array("qos"=>0, "function"=>"procmsg");
$mqtt->subscribe($topics,0);
while($mqtt->proc()){
}
$mqtt->close();
function procmsg($topic,$msg){
echo "Msg Recieved: $msg";
}
Here is the phpMQTT.php file: https://github.com/bluerhinos/phpMQTT/blob/master/phpMQTT.php
However, the issue in this case is that it recieves data only when the webpage is open.. I want to keep the connection alive even if the webpage is not open to always recieve published messages, how can I do it?
EDIT : I might be open to using some other technology on the server to handle this subscription process, if anyone can recommend some alternatives

PHP's typically mode of operation is to start a process, wait for an HTTP connection, handle the request and then start a new process. This doesn't fit well with the typical MQTT mode of having a long-running process; hence closing the MQTT connection when you close the web page.
It is possible to subscribe to a MQTT topic in a long-running CLI PHP script, but you will have to have some other mechanism to keep the process running. There are a lot of different ways of doing this, depending on your preferences and operating system:
a script started using /etc/rc.local at system startup
using a init.d script
using a process manager, such as DJB's daemontools or runit
If you are using Ubuntu, then upstart is a popular mechanism
Searching stackoverflow finds the following related question and several answers:
Run php script as daemon process

Related

PHP Fatal error: Uncaught PDOException: SQLSTATE[HY000] [2002] on heavy query [duplicate]

Sometimes I get the following error while I was doing HttpWebRequest to a WebService. I copied my code below too.
System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it 127.0.0.1:80
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetRequestStream()
ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.PreAuthenticate = true;
request.Credentials = networkCredential(sla);
request.Method = WebRequestMethods.Http.Post;
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = v_Timeout * 1000;
if (url.IndexOf("asmx") > 0 && parStartIndex > 0)
{
AppHelper.Logger.Append("#############" + sla.ServiceName);
using (StreamWriter reqWriter = new StreamWriter(request.GetRequestStream()))
{
while (true)
{
int index01 = parList.Length;
int index02 = parList.IndexOf("=");
if (parList.IndexOf("&") > 0)
index01 = parList.IndexOf("&");
string parName = parList.Substring(0, index02);
string parValue = parList.Substring(index02 + 1, index01 - index02 - 1);
reqWriter.Write("{0}={1}", HttpUtility.UrlEncode(parName), HttpUtility.UrlEncode(parValue));
if (index01 == parList.Length)
break;
reqWriter.Write("&");
parList = parList.Substring(index01 + 1);
}
}
}
else
{
request.ContentLength = 0;
}
response = (HttpWebResponse)request.GetResponse();
If this happens always, it literally means that the machine exists but that it has no services listening on the specified port, or there is a firewall stopping you.
If it happens occasionally - you used the word "sometimes" - and retrying succeeds, it is likely because the server has a full 'backlog'.
When you are waiting to be accepted on a listening socket, you are placed in a backlog. This backlog is finite and quite short - values of 1, 2 or 3 are not unusual - and so the OS might be unable to queue your request for the 'accept' to consume.
The backlog is a parameter on the listen function - all languages and platforms have basically the same API in this regard, even the C# one. This parameter is often configurable if you control the server, and is likely read from some settings file or the registry. Investigate how to configure your server.
If you wrote the server, you might have heavy processing in the accept of your socket, and this can be better moved to a separate worker-thread so your accept is always ready to receive connections. There are various architecture choices you can explore that mitigate queuing up clients and processing them sequentially.
Regardless of whether you can increase the server backlog, you do need retry logic in your client code to cope with this issue - as even with a long backlog the server might be receiving lots of other requests on that port at that time.
There is a rare possibility where a NAT router would give this error should its ports for mappings be exhausted. I think we can discard this possibility as too much of a long shot though, since the router has 64K simultaneous connections to the same destination address/port before exhaustion.
The most probable reason is a Firewall.
This article contains a set of reasons, which may be useful to you.
From the article, possible reasons could be:
FTP server settings
Software/Personal Firewall Settings
Multiple Software/Personal Firewalls
Anti-virus Software
LSP Layer
Router Firmware
Computer Turned Off
Computer Not Plugged In
Fiddler
I had the same. It was because the port-number of the web service was changing unexpectedly.
This problem usually happens when you have more than one copy of the project
My project was calling the Web service with a specific port number which I assigned in the Web.Config file of my main project file. As the port number changed unexpectedly, the browser was unable to find the Web service and throwing that error.
I solved this by following the below steps: (Visual Studio 2010)
Go to Properties of the Web service project --> click on Web tab --> In Servers section --> Check Specific port
and then assign the standard port number by which your main project is calling the web service.
I hope this will solve the problem.
Cheers :)
I think, you need to check your proxy settings in "internet options". If you are using proxy/'hide ip' applications, this problem may be occurs.
I had the same problem. The problem is that I didn't start the selenium server. I have downloaded the selenium server and i started it. After starting the selenium server, issue gone and all worked fine.
Refer this : http://coding-issues.blogspot.in/2012/11/no-connection-could-be-made-because.html
I had the same error with my WCF service using Net TCP binding, but resolved after starting the below services in my case.
Net.Pipe.Listener.Adapter
Net.TCP.Listener.Adapter
Net.Tcp Port Sharing Service
In my case, some domains worked, while some did not. Adding a reference to my organization's proxy Url in my web.config fixed the issue.
<system.net>
<defaultProxy useDefaultCredentials="true">
<proxy proxyaddress="http://proxy.my-org.com/" usesystemdefault="True"/>
</defaultProxy>
</system.net>
When you call service which has only HTTP (ex: http://example.com) and you call HTTPS (ex: https://example.com), you get exactly this error - "No connection could be made because the target machine actively refused it"
I faced same error because when your Server and Client run on same machine the Client need server local ip address not Public ip address to communicate with server you need Public ip address only in case when Server and Client run on separate machine so use Local ip address in client program to connect with server Local ip address can be found using this method.
public static string Getlocalip()
{
try
{
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
return localIPs[7].ToString();
}
catch (Exception)
{
return "null";
}
}
I got this error in an application that uses AppFabric. The clue was getting a DataCacheException in the stack trace. To see if this is the issue for you, run the following PowerShell command:
#("AppFabricCachingService","RemoteRegistry") | % { get-service $_ }
If either of these two services are stopped, then you will get this error.
For me, I wanted to start the mongo in shell (irrelevant of the exact context of the question, but having the same error message before even starting the mongo in shell)
The process 'MongoDB Service' wasn't running in Services
Start cmd as Administrator and type,
net start MongoDB
Just to see MongoDB is up and running just type mongo, in cmd it will give Mongo version details and Mongo Connection URL
Well, I've received this error today on Windows 8 64-bit out of the blue, for the first time, and it turns out my my.ini had been reset, and the bin/mysqld file had been deleted, among other items in the "Program Files/MySQL/MySQL Server 5.6" folder.
To fix it, I had to run the MySQL installer again, installing only the server, and copy a recent version of the my.ini file from "ProgramData/MySQL/MySQL Server 5.6", named my_2014-03-28T15-51-20.ini in my case (don't know how or why that got copied there so recently) back into "Program Files/MySQL/MySQL Server 5.6".
The only change to the system since MySQL worked was the installation of Native Instruments' Traktor 2 and a Traktor Audio 2 sound card, which really shouldn't have caused this problem, and no one else has used the system besides me. If anyone has a clue, it would be kind of you to comment to prevent this for me and anyone else who has encountered this.
For service reference within a solution.
Restart your workstation
Rebuild your solution
Update service reference in WCFclient project
At this point, I received messsage (Windows 7) to allow system access.
Then the service reference was updated properly without errors.
I would like to share this answer I found because the cause of the problem was not the firewall or the process not listening correctly, it was the code sample provided from Microsoft that I used.
https://msdn.microsoft.com/en-us/library/system.net.sockets.socket%28v=vs.110%29.aspx
I implemented this function almost exactly as written, but what happened is I got this error:
2016-01-05 12:00:48,075 [10] ERROR - The error is: System.Net.Sockets.SocketException (0x80004005): No connection could be made because the target machine actively refused it [fe80::caa:745:a1da:e6f1%11]:4080
This code would say the socket is connected, but not under the correct IP address actually needed for proper communication. (Provided by Microsoft)
private static Socket ConnectSocket(string server, int port)
{
Socket s = null;
IPHostEntry hostEntry = null;
// Get host related information.
hostEntry = Dns.GetHostEntry(server);
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
foreach(IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, port);
Socket tempSocket =
new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Connect(ipe);
if(tempSocket.Connected)
{
s = tempSocket;
break;
}
else
{
continue;
}
}
return s;
}
I re-wrote the code to just use the first valid IP it finds. I am only concerned with IPV4 using this, but it works with localhost, 127.0.0.1, and the actually IP address of you network card, where the example provided by Microsoft failed!
private Socket ConnectSocket(string server, int port)
{
Socket s = null;
try
{
// Get host related information.
IPAddress[] ips;
ips = Dns.GetHostAddresses(server);
Socket tempSocket = null;
IPEndPoint ipe = null;
ipe = new IPEndPoint((IPAddress)ips.GetValue(0), port);
tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Platform.Log(LogLevel.Info, "Attempting socket connection to " + ips.GetValue(0).ToString() + " on port " + port.ToString());
tempSocket.Connect(ipe);
if (tempSocket.Connected)
{
s = tempSocket;
s.SendTimeout = Coordinate.HL7SendTimeout;
s.ReceiveTimeout = Coordinate.HL7ReceiveTimeout;
}
else
{
return null;
}
return s;
}
catch (Exception e)
{
Platform.Log(LogLevel.Error, "Error creating socket connection to " + server + " on port " + port.ToString());
Platform.Log(LogLevel.Error, "The error is: " + e.ToString());
if (g_NoOutputForThreading == false)
rtbResponse.AppendText("Error creating socket connection to " + server + " on port " + port.ToString());
return null;
}
}
This is really specific, but if you receive this error after trying to connect to a database using mongo, what worked for me was running mongod.exe before running mongo.exe and then the connection worked fine. Hope this helps someone.
One more possibility --
Make sure you're trying to open the same IP address as where you're listening. My server app was listening to the host machine's IP address using IPv6, but the client was attempting to connect on the host machine's IPv4 address.
I've received this error from referencing services located on a WCFHost from my web tier. What worked for me may not apply to everyone, but I'm leaving this answer for those whom it may. The port number for my WCFHost was randomly updated by IIS, I simply had to update the end routes to the svc references in my web config. Problem solved.
In my scenario, I have two applications:
App1
App2
Assumption: App1 should listen to App2's activities on Port 5000
Error: Starting App1 and trying to listen, to a nonexistent ghost town, produces the error
Solution: Start App2 first, then try to listen using App1
Go to your WCF project -
properties ->
->
debuggers
-> unmark the checkbox
Enable Edit and Continue
In my case this was caused by a faulty deployment where a setting in my web.config was not made.
A collegue explained that the IP address in the error message represents the localhost.
When I corrected the web.config I was then using the correct url to make the server calls and it worked.
I thought I would post this in case it might help someone.
Using WampServer 64bit on Windows 7 Home Premium 64bit I encountered this exact problem. After hours and hours of experimentation it became apparent that all that was needed was in my.ini to comment out one line. Then it worked fine.
commented out 1 line
socket=mysql
If you put your old /data/ files in the appropriate location, WampServer will accept all of them except for the /mysql/ folder which it over writes. So then I simply imported a backup of the /mysql/ user data from my prior development environment and ran FLUSH PRIVILEGES in a phpMyAdmin SQL window. Works great. Something must be wrong because things shouldn't be this easy.
I had this issue happening often. I found SQL Server Agent service was not running. Once I started the service manually, it got fixed. Double check if the service is running or not:
Run prompt, type services.msc and hit enter
Find the service name - SQL Server Agent(Instance Name)
If SQL Server Agent is not running, double-click the service to open properties window. Then click on Start button. Hope it will help someone.
I came across this error and took some time to resolve it. In my case I had https and net.tcp configured as IIS bindings on same port. Obviously you can't have two things on the same port. I used netstat -ap tcp command to check whether there is something listening on that port. There was none listening. Removing unnecessary binding (https in my case) solved my issue.
It was a silly issue on my side, I had added a defaultproxy to my web.config in order to intercept traffic in Fiddler, and then forgot to remove it!
There is a service called "SQL Server Browser" that provides SQL Server connection information to clients.
In my case, none of the existing solutions worked because this service was not running. I resumed it and everything went back to working perfectly.
I was facing this issue today. Mine was Asp.Net Core API and it uses Postgresql as the database. We have configured this database as a Docker container. So the first step I did was to check whether I am able to access the database or not. To do that I searched for PgAdmin in the start as I have configured the same. Clicking on the resulted application will redirect you to the http://127.0.0.1:23722/browser/. There you can try access your database on the left menu. For me I was getting an error as in the below image.
Enter the password and try whether you are able to access it or not. For me it was not working. As it is a Docker container, I decided to restart my Docker desktop, to do that right click on the docker icon in the task bar and click restart.
Once after restarting the Docker, I was able to login and see the Database and also the error was gone when I restart the application in Visual Studio.
Hope it helps.
it might be because of authorisation issues; that was the case for me.
If you have for example: [Authorize("WriteAccess")] or [Authorize("ReadAccess")] at the top of your controller functions, try to comment them out.
I just faced this right now...
Here on my end, I have 2 separated Visual Studio solutions (.sln)... opened each one in their own Visual Studio instance.
Solution 2 calls Solution 1 code. The problem was related to the port assigned to Solution 1. I had to change the port on solution 1 to another one and then Solution 2 started working again. So make sure you check the port assigned to your project.
Normally, connection scripts do not mention the port to use. For example:
$mysqli = mysqli_connect('127.0.0.0.1', 'user', 'password', 'database');
So, to connect with a manager that doesn't use port 3306, you have to specify the port number on the connection request:
$mysqli = mysqli_connect('127.0.0.0.1', 'user', 'password', 'database', '3307');
To check the connections on the MySQL or MariaDB database manager, use the script:
wamp(64)\www\testmysql.php
by putting 'http://localhost/testmysql.php' in the browser address bar having first modified the script according to your parameters.
I forgot to start the service so it failed because no service was listening on port.
Resolved by starting the service.

Shutting down a socket in PHP

I created a cache server and client in php, no need to ask why, just for fun. The implementation works, but a problem occures every time when:
Server starts
Client connects
Server stores data
Client disconnects
When I stop the running server process, after a client disconnects and trying to restart the server, the socket_bind throws an error, that the address is already in use. The client always closes connection after the data has been sent or recieved and when I check if the port is in use via sudo netstat, the port is not listed. The server looks like this:
public function run()
{
$this->socket = $this->ioHandler->createServerSocket();
while ($this->running) {
while ($connection = #socket_accept($this->socket)) {
socket_set_nonblock($connection);
$this->maintainer->maintainBucket($this->bucket);
$this->maintainer->checkBackup(time(), $this->bucket);
try {
$dataString = $this->ioHandler->readFromSocket($connection);
$data = unserialize($dataString);
($this->actionHandler)($data, $this->bucket, $this->ioHandler, $connection);
} catch (Exception $ex) {
$this->ioHandler->writeToSocket($connection, self::NACK);
$this->ioHandler->closeSocket($connection);
}
}
}
}
I think the problem might be that the server shuts down via a simple ctrl+c or a start-stop-daemon --stop --pidfile and the socket is still open and there might be some automatized service that cleans up dead sockets. How can I properly shut down the server? Can I somehow terminate the process by sending an input via STDIN to kill the server socket? Or am I wrong on the issue? The full code is available on github: https://github.com/dude920228/php-cache
Perhaps it's related to TIME_WAIT state. Long story short - socket_close() may close the socket, but there still may be data to send. Until the data is sent, the port will not be available.
More info is:
here
here
and here

Socket connection on same machine, PHP to C++ and back

I had to implement a communication between an application written in c++ and a web server scripted with PHP.
The basic idea was to create a socket with the c++ application, binding it and listen for the PHP connection to it.
The PHP would then send a message over TCP asking for data and the c++ would send back the answer. Single header request, single string(JSON) answer.
So far, so good.
This is the code I used for the PHP side:
<?php
error_reporting(E_ALL);
$service_port = 8080;
$address = 'localhost';
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
}
echo "Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
}
$in = "request1";
$out = '';
socket_write($socket, $in, strlen($in));
$buf = 'This is my buffer.';
if (false !== ($bytes = socket_recv($socket, $buf, 2048, MSG_WAITALL))) {
echo "Read $bytes bytes from socket_recv(). Closing socket...";
} else {
echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($socket)) . "\n";
}
socket_close($socket);
echo $buf . "\n";
//elaborate the $buf
?>
Now I would like to implement also an auto-update of the data, with the c++ (server side) sending data and the PHP side(client side) to collect them.
The data update should be done every minute.
Sadly I don't have much experience with web developing, so I'm kindly asking some advices on that.
The easiest thing I could do was looping the PHP code untill a known message got received. The problem I faced is that I don't get data untill the loop is over and the PHP script ends.
To overcome the problem I tried to set PHP side the socket to be non-blocking
replacing in the socket_recv the option MSG_WAITALL with MSG_DONTWAIT but nothing changed. Then I tried to break out of the PHP script, but it can't be done since I need to cycle it to get the data every second.
Plus I get another problem, during the loop cycles, the apache server the PHP is running on is getting a 503 error, Server Unavailable.
I don't know why it happens, maybe the received message buffer is full, or the script takes too many resources.
Due to my lack of experience I can't understand why.
I know there are good libraries to perform what I need but I'm working on an embedded machine so I'm limited to work with basic libraries.
How can I achieve the PHP on the Apache server to get timed data from the c++ application ? What am I overlooking ?
Thanks a lot in advance for your help.
Edit: Deleted rhetorical question.
Using php to obtain data from another process via tcp/ip will require a bit more effort compared to sending data from a php script executed via apache to another process using tcp/ip sockets.
Your php script will need to be started outside of apache and will require an infinite loop that continuously listens to the given port to read input data. The following post outlines what I believe you are after.
EDIT
In order to display the results on the web page you could use an in memory data store such as Redis. The php server application would update a data structure in redis, then the webpage onload could pull the latest value from redis and display it on screen, however this would require a page refresh.
If you require that the data be refreshed immediately once received without server postback, this will require some javascript. When a user loads the page you would initialize a websocket connection with a websocket server (people generally use node.js and socket.io for implementing this but you can code a websocket server in anything that supports the technology). The websocket server would be subscribed to a redis channel that when updated would send the new values to all connected clients. I suppose this could be done without redis as well depending on what your requirements are. The program for the websocket server could also be the server that accepts the information from your c++ program using a separate thread. When data comes in from the c++ program you could then send it directly to the clients connected via websocket.
Don't reinvent the wheel. Use a websockets. It's designed to do this async communication and you can send JSON over it just fine.
There are libraries for C++ and PHP, meaning this should be pretty easy.

Sending messages from PHP script to multiple Ratchet Websocket apps (via ZMQ Socket)

So, I am running a Ratchet (php) websocket server with multiple routes that connect do multiple Ratchet apps (MessageComponentInterfaces):
//loop
$loop = \React\EventLoop\Factory::create();
//websocket app
$app = new Ratchet\App('ws://www.websocketserver.com', 8080, '0.0.0.0', $loop);
/*
* load routes
*/
$routeOne = '/example/route';
$routeOneApp = new RouteOneApp();
$app->route($routeOne, $routeOneApp, array('*'));
$routeTwo = '/another/route';
$routeTwoApp = new AnotherApp();
$app->route($routeTwo, $routeTwoApp, array('*'));
From here I am binding a ZMQ socket, in order to be able to receive messages sent from php scripts run on the normal apache server.
// Listen for the web server to make a ZeroMQ push after an ajax request
$context = new \React\ZMQ\Context($loop);
$pull = $context->getSocket(\ZMQ::SOCKET_PULL);
$pull->bind('tcp://127.0.0.1:5050'); // Binding to 127.0.0.1 means the only client that can connect is itself
$pull->on('message', array($routeOneApp, 'onServerMessage'));
Finally, the server is started:
//run
$loop->run();
This works perfectly fine as long as i am binding only one of the ratchet apps to the ZMQ socket. However, i would like to be able to separately push messages to both of the Ratchet apps. For this purpose i thought of binding two ZMQ sockets to different routes like:
$pullOne->bind('tcp://127.0.0.1:5050' . $routeOne); // Binding to 127.0.0.1 means the only client that can connect is itself
$pullOne->on('message', array($routeOneApp, 'onServerMessage'));
and
$pullTwo->bind('tcp://127.0.0.1:5050' . $routeTwo); // Binding to 127.0.0.1 means the only client that can connect is itself
$pullTwo->on('message', array($routeTwoApp, 'onServerMessage'));
However, this leads to an error message from ZMQ when binding the second socket, saying the given address is already in use.
So the question is, is there any other way to use routes over a ZMQ socket?
Or should i use other means to distinguish between messages for the separate Ratchet apps, and if so, what would be a good solution?
I thought about binding to 2 different ports, but figured that would be a pretty ugly solution?!
In general in TCP packets are identified by the 4 tuple (sender ip, sender port, receiver ip, receiver port).
When a incoming packet reaches the network layer, it is forwarded to the appropriate application by looking at the receiver ip and port. If you use the same pair for both the apps, it will be impossible for the layer to decide whom to send it to when a connection comes in.
One solution would be to bind a single connection and the write a common handler that looks at the incoming content and then decides (I assume you have some logic) to differentiate the incoming connections to the different instances and then invokes the corresponding handler. The handler can get the connection object and can handle the connection hence forth.
If both your instances are identical and it doesn't matter who gets the request then you can just randomly forward the new connection to any of the handler.
Edit: I have tried to answer the question irrespective of the application type (Racket/ZMQ etc) because the issue you are trying to address is a fundamental one common to any network application.
For this case since you have two apps running and want to listen on the same port, you can have a common handler which can look at the request URL and forward the connection to the appropriate handler.
The request URL can be obtained using
$querystring = $conn->WebSocket->request->getQuery();
Now the clients can connect using
ws://localhost:5050/app1
and
ws://localhost:5050/app2
Your different apps can now handle these connections separately.

How can I set Realtime WebSocket buffer?

I am working on a realtime multiplayer game which was built using Ratchet 0.3.3, Laravel 5 and PHP 5.5.9, The server OS is Ubuntu. The server sends approximately 500 bytes of data in each cycle to every user via WebSocket (hundreds of users).
It looks like WebSocket is buffering the requests and sends 5 to 6 requests at once (500 bytes each).
We have 30 millisecond cycles. Is there a way to manually set the WebSocket buffer settings , so my requests can be sent with no delays ?
I found a solution for that problem. First, IoServer class created and extend IoServer from Ratchet.
class IoServer extends \Ratchet\Server\IoServer {
public static function factory(MessageComponentInterface $component, $port = 80, $address = '0.0.0.0') {
$loop = LoopFactory::create();
$socket = new Reactor($loop);
$socket->listen($port, $address);
$sock = socket_import_stream($socket->master);
socket_set_option($sock, SOL_TCP, TCP_NODELAY, true);
return new static($component, $socket, $loop);
}
}
Azure itself does not have any certain restrictions on the buffer setting for the Ubuntu VM. First I would check the current buffer setting values using the commands listed here - How to find the socket buffer size of linux.
Secondly, if you want to configure or tune them, you can refer - http://www.cyberciti.biz/faq/linux-tcp-tuning/
Not sure if this is the answer you are looking for, as Ghedipunk pointed, it might be a issue of Nagle's algo, in which case, you might want to try adding the tcp_nodelay configuration in the tunnel configurations -
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
though I personally never worked with Ratchet.
PS- I wanted to add this as a comment as I am not sure this is the correct answer you are looking for, but SO forum is not allowing me to add a comment.

Categories