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.
Related
This must be simple and I suspect I have disappeared down the wrong rabbit hole.
I have the apache http server running on a pi serving pages (LAMP server) exposed through our domestic router. I can get php to serve up the material I want, and thought it would be easy to get php (on the server) to talk via sockets to another machine on the local network (ie 192.168.1.73 for example)
I can get data from a web page via the server to the local machine, but cannot get the server to receive messages from the local machine. In php the call to
'''
socket_bind(...)
'''
gives the error
"unable to bind address [99]: Cannot assign requested address"
Don't know where the 99 is coming from; installed and ran ufw to open the port I'm using (would not have thought that was necessary or desirable but tried it anyway)
Any help greatly appreciated.
P
It is a PHP problem.
Implemented "quote of the day" in java, running the client on the same machine as my problematic php, and the quote server on another machine on the local network. That works fine. replace the java client with this php client:
<?php
$server_ip = '192.168.1.78';
$port = 41235;
$message = 'hello world.';
$buf = [];
$skt = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP) or die(..);
socket_sendto($skt,$message,strlen($message),0,$server_ip,$port);
// message is successfully sent and received at other end...
socket_bind($skt,$server_ip,$port)
or die("Could not bind socket\n");
// the bind fails
$bc = socket_recvfrom($skt,$buf,256,0,$server_ip,$port);
echo "Got $bc bytes back";
?>
Fails as above with error [99]
The use-case is to run a server on a machine inside a local network -lets call it insideServer, and have requests from a webpage hosted on a machine, outsideServer, responded to by code running on insideServer. Why? InsideServer's server is written in java because I like it. The right way to do this was, in the old days, to have java running on the user's machine as an applet; The modern way would be to have outsideServer run Apache Tomcat. I don't however have the luxury of doing that so how does one forward requests?
The solution is to have a PHP script in the relevant directory of outsideServer that connects via sockets to insideServer where insideServer's code can be in whatever you want. The PHP has however been problematic. This code does work however:
$insideServerIP = '192.168.1.78';
$insideServerPort = 41234;
$message = 'pretend message from web page form';
$skt = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP) or die("create failed: " . socket_last_error());
socket_connect($skt, $insideServerIP, $insideServerPort) or die("connect failed: " . socket_last_error());
socket_write($skt, $message, strlen($message));
$in = socket_read($skt, 256, PHP_BINARY_READ);
echo "$in\n";
socket_close($skt);
My research over the last few days (Arr!!!) suggests nobody knows how socket_bind() is meant to work, and it turns out you don't need it!
Please do post comments (or a better answer) if there are mistakes, but this solution works I believe.
P
I am implementing my custom XMPP PHP library (Packagist repo) and I have trouble fetching messages (that the client sent) from XMPP server.
Library is using PHP sockets to connect to the server, and I am able to fetch a response from server when initially connecting and authenticating. I can also send a message from server to the client, and that part works.
I can't however receive a message.
This is the code I am using when receiving anything from server:
public function getRawResponse()
{
// Wait max 3 seconds before terminating the socket
socket_set_option($this->socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => $this->options->getSocketWaitPeriod(), "usec" => 0]);
while ($out = socket_read($this->socket, 2048)) {
echo "*** Data ***\n\n";
echo str_replace("><", ">\n<", $out) . "\n\n";
echo "\n\n************\n";
}
}
This while loop is here to fetch all one-batch responses from the server, and it reads from server while it has something to read, otherwise it terminates the connection.
In the main program I am thus doing a do{...}while(true) and putting this method inside so that it doesn't terminate ever. But still I am not getting any response when sending the other way around, from client back to server.
I have found that I needed to send initial empty presence stanza to server
<presence/>
Once I got the server response back, so did the message responses started incoming.
I have a webserver which serves the client with an octet stream on port 20000 (it's actually a socket.io server hosted with node.js). This is running on a shared hosting account with a regular Apache server running on port 80 (this cannot be turned off, hence the socket.io server is on port 20000). Due to firewalls and such, I cannot expect the user to be able to connect to port 20000 (or any other than 80). So, how can I serve the client with the octet stream produced by the socket.io server from the Apache server (sort of like a reverse proxy)? Unfortunately I cannot use mod_proxy on my Apache server given restraints of my hosting plan. I was thinking I could do this with a PHP page that opens a socket somehow.
Update: I also have Django for Python 3 installed on my server which could be useful. Please note that the proxy cannot simply request the target page and serve it back to the client since the data has to be transferred in real time.
Re "it cannot simply serve the target page back" ... this is not true because this is all an HTTP proxy is. Most protocol proxies use a socket (versus a file or pipe) and simply copy the data from socket to socket. An HTTP proxy does the same thing except every HTTP request requires a handshake, so the proxy will require a few packets back and forth before reaching the payload. You can create an HTTP GET proxy very easily in django. A POST proxy will need extra footwork.
I am not familiar with Socket.IO, but upon researching ... how does socket.io work? ... it appears it uses only "old" HTTP features and runs everything as REST. The REST is encapsulated as a transport inside of a persistent socket.
If you were looking for an TCP or IP-level proxy within Django, its not going to happen. Your apache server, and then WSGI/CGI/whatever closes the TCP socket off from you. The only way you'll be able to access it is with sufficient permissions to those parts of the server.
Here's what I'd do ... In django make a url pattern that captures the socket.io api, and have it connect to a view that does something like the following (untested pseudo code):
import urllib2, mimetypes
from django.http import HttpResponse
def ForwardToSocketIO(request):
# Capture the URL pattern
path = request.get_full_path()
# Create a URL opener
response = urllib2.urlopen('http://localhost:20000%s' % path)
# Capture and return response
django_response = HttpResponse(response.read())
django_response['Content-Type'] = 'octet-stream'
return django_response
Hope this helps. I don't have an octet stream available so apologies for not testing.
Seems possible not impossible. I have not done it before but know the way to do but again I don't know the impact of Firewall on port openning and closing. The basic Idea about doing thing is:
Get you request from port 80 to do things and for response of that request use different port to communicate with client. It would become a tunnel to recieve request from one port and get reply from the other port. Only one thing to be properly taken care of that termination of connection as soon as possible once the purpose is resolve unless it would create memory load on the server.
With the below example you can do the above things but suggest you to use them with caution and after proper testing.
ref: Programming with Sockets through PHP
This example shows a simple talkback server. Change the address and port variables to suit your setup and execute. You may then connect to the server with a command similar to: telnet 192.168.1.53 10000 (where the address and port match your setup). Anything you type will then be output on the server side, and echoed back to you. To disconnect, enter 'quit'.
<?php
error_reporting(E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Get the port for the WWW service. */
$service_port = getservbyname('www', 'tcp');
/* Get the IP address for the target host. */
$address = gethostbyname('www.example.com');
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " .
socket_strerror(socket_last_error()) . "\n";
} else {
echo "OK.\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";
} else {
echo "OK.\n";
}
$in = "HEAD / HTTP/1.1\r\n";
$in .= "Host: www.example.com\r\n";
$in .= "Connection: Close\r\n\r\n";
$out = '';
echo "Sending HTTP HEAD request...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";
echo "Reading response:\n\n";
while ($out = socket_read($socket, 2048)) {
echo $out;
}
echo "Closing socket...";
socket_close($socket);
echo "OK.\n\n";
?>
I am stuck with this problem. I am using a server ( I have full excess rights and can do anything ). On this, I want to run a file which will connect to a port and receive data from devices. These devices will send data using TCP.
Server file should run continuously, 24x7, without any break. But it is not happening. To understand deeper I am pasting the code.
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
$result = socket_listen($socket) or die("Could not set up socket listener\n");
while(true) {
if ($spawn = socket_accept($socket)) {
if ($input = socket_read($spawn, 1024)) {
// MY REST OF THE CODE HERE
}
socket_close($spawn);
unset($spawn);
}
}
In line number 5, server will accept the connection and next loop will be executed. It goes well if devices are sending data continuously. It will wait for device and once receive data, it will proceed further. But after some hours, server file stops responding. Port is consumed but server does not work on data. I made a client file to test whether port is working or not. Client file successfully connected with server.
What should I do to run this file continuously 24x7 without error.
One more thing I want to ask is, what if for some time device stops sending data ? Will it affect line 5 ? and this will lead to file hang ?
I'm very new to PHP so this might be something simple. Anyway, I'm trying to create 2-way communication between a PHP script (activated by a web client) and a local process (written in C++). The PHP script should send some information to the C++ process and then wait for a response. My problem is that the only way to set up this kind of communication seems to be to use socket_bind, but when I do, it fails with the 'address already in use' error. The socket file in question, /tmp/sock, has already been created by the C++ process, which is running continuously (it can not be launched by the PHP script). If I use socket_connect and just write something to the C++ process, that works just fine; but I need to bind before I can listen to that socket from the PHP script. Here's my code:
<?php
error_reporting(E_ALL);
/* Allow the script to hang around waiting for connections. */
set_time_limit(0);
/* Turn on implicit output flushing so we see what we're getting
* as it comes in. */
ob_implicit_flush();
//Adapted from http://www.php.net/manual/en/sockets.examples.php
if (($sock = socket_create(AF_UNIX, SOCK_STREAM,0)) === false)
{
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
exit();
}
if (socket_bind($sock, '/tmp/sock') === false) //Fails here
{
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
....
Thanks--
Your C++ and PHP codes have to mark the socket as shared (SO_REUSE_ADDR).
It turns out that what's needed is simply socket_read(). I didn't realize you could do both operations on the same socket (when it was merely connected and not bound). User hamishcool3 at PHP socket_read has a great utility function for reading from a socket until a particular character is reached (though it is probably slower than a standard byte-limited read).