I have a server running and waiting/listening for connections. The server is based on Mark Framework which is using Workerman. So far I'm able to start the server and when I load the URL/host on the browser it shows content (in this case I'm expecting a simple Hello world).
This is index.php which I use to start the server
use Mark\App;
require 'vendor/autoload.php';
$api = new App('http://127.0.0.1:8080');
$api->count = 2; // process count
$api->any('/', function ($requst) {
return 'Hello world';
});
$api->start();
Now, I have a simple Laravel app that I want when I open a certain page to connect to that server and show the content from it.
I'm not sure how to do this. What I have so far in the controller is this
public function index() {
try {
$host = "127.0.0.1";
$port = 8080;
$resource = stream_socket_client("tcp://$host:$port", $error_no, $error_str, 20, STREAM_CLIENT_CONNECT);
$lines = stream_get_line($resource, 8192);
var_dump($lines);
} catch(Exception $e){
return response($e->getMessage(), 500);
}
var_dump($resource);
return View::make('index');
}
var_dump($resource) which is a variable for the connection shows
resource(10) of type (stream)
var_dump($lines); shows false which I guess is because the $resource doesn't make any connection
bool(false)
Any ideas here on how to approach this?
TCP connection does not rely on any protocol, it's just a pure data transfer protocol which enables you to transfer bytes with ACL confirmation. You name it TCP and you include some Mark Framework which is http protocol based process.
The docs say it helps you to quickly write APIs with php. It means it's not a TCP raw server with custom protocol but it is a http protocol oriented server which is simply a REST API ready for http GET/POST requests to make your life easier.
You can do the same things with laravel on both sides until you need realtime connection. Realtime socket connections are made via javascript because HTTP is not built for this.
From laravel side just read: https://laravel.com/docs/9.x/http-client#making-requests
I might overwatched something, but sockets are rarely used in web. By calling TCP you called for 'sockets' and your post seems to negate your need for them.
Related
I'm trying to receive UDP data from a game. And update it on the page constantly. Using JSON to retrieve the data from a function.
Is it possible to separate socket_create/socket_bind from socket_recvfrom?
(I've cut some unnecessary code out of it)
private $socket;
public function socketConnect($port)
{
$ip = '0.0.0.0'; // local IP
$port = 20777; // port to listen
$this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($this->socket, $ip, $port) or die("Could not connect");
return view('telemetry');
}
public function getData()
{
while (socket_recvfrom($this->socket, $buf, $bytes, 0, $remote_ip, $remote_port)) {
// do something
return response()->json($data);
}
}
I've tried setting $this->socket to keep the data but that doesn't seem to work.
You cannot do that, no. Sockets created with the socket_* methods are not persistent, since they are low level sockets. And here your two functions are executed in two different page calls that are independent from each other (this is how PHP works).
Furthermore, what you are trying to do right now is a socket server (binding a socket is for server purposes usually), and socket servers need to be open continually to receive data. I would advise you to try to do a CLI program (that can still be done in PHP) and use the socket_recvfrom and socket_sendto methods to get and send your data (after doing your bind), and then store the received data in a database or in a file, to then have your website read from that to send it to your browser. Here is a howto that shows how to create a simple UDP server in PHP.
Hello I'm quite new to using sockets and am not that familiar with them yet, Basically all i am trying to do is pass a string variable to a web address (e.g. www.example.com/index.php?Example=StringExample) and then get a response, so for example it would return "Test Example" if index.php looked like this:
<?php
if($_GET['Example'] == "StringExample")
{
echo "Test Example";
}
?>
Here is what I've tried in c++:
struct sockaddr_in SocketAddress;
hostent* addr = gethostbyname("www.example.com/index.php?Example=StringExample");
int sizeofaddr = sizeof(addr);
SocketAddress.sin_addr.s_addr = inet_addr(addr->h_name);
SocketAddress.sin_port = htons(80);
SocketAddress.sin_family = AF_INET;
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL);
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0)
{
return 0; //Failed to Connect
}
char buffff[256];
recv(Connection, buffff, sizeof(buffff), NULL);
//"Test Example" now stored in buffff
What am i doing wrong?
Btw in my case i would not like to use any libraries like boost or anything like that. Thanks for the help :)
gethostbyname("www.example.com/index.php?Example=StringExample");
"www.example.com/index.php?Example=StringExample" is not a valid server name. This is an entire URL; a server name would be "www.example.com". gethostbyname() takes the name of a server, and not a URL, and returns its IP address. Additionally, gethostbyname() has been obsoleted. New code should use the getaddrinfo(3) function, instead.
This is obviously an HTTP URL. To download a document via HTTP it is a lot more work than just connecting a socket. Establishing a socket connection is just the first step in the process of downloading a document from an HTTP server. This must be followed by sending a valid HTTP request, and then receiving an HTTP response from the server.
There are many libraries, such as curl, that implement the entire client-side process needed to download an HTTP document, that will handle the socket connection themselves.
But there's nothing wrong with trying to implement this yourself, either. It's a good programming excersize.
So, after resolving www.example.com's IP address, you will need to
1) Connect to the server's port 80, the default HTTP port.
2) Send an HTTP request for "/index.php?Example=StringExample".
3) Parse the HTTP response.
The specification for HTTP requests and responses is defined by RFC 2616, which you can consult for complete documentation of how HTTP requests and responses are structured.
If you want to access a web server with sockets, you have to keep in mind:
You can open a tcp/ip connection to your web server
BUT afterwards you have to do the http protocol by yourself
In case of your example:
hostent* addr = gethostbyname("www.example.com");
//...
const char* request = "GET index.html"
send(Connection, request, strlen(request), NULL)
//fetch index.html with a recv and parse it
To be more precise, if you want to access your server, you have to take a look how GET, PUT, POST, etc. are implemented in the http protocol, send the proper commands to your web server and recv() the replies
I'm in the process of creating my own service status script as both a chance to become more familiar with the PHP language and to design it from the ground up as being as efficient as possible for my needs.
A section of my code used in both my cron job and testing a connection parts queries the IP/Port of a service to make sure it is online. My issue is that the script simply queries whether the port is "Unblocked" on that IP so if for instance I was querying port 21 with an FTP server and that FTP server crashed my script would not detect any changes meaning its not doing what I want it to do. Instead I would be wanting the IP and port to be queried and for my script to see if there is actually something running on that port, if there is show online if not error out. I've had a look on google and it seems like I would have to send a packet/receive a response so PHP can tell there's something active? I'm not sure.
This is my current code below:
<?php
$host = $_POST['servip'];
$port = $_POST['servport'];
if (!$socket = #fsockopen($host, $port, $errno, $errstr, 3)) {
echo "Offline!";
} else {
echo "Online!";
fclose($socket);
}
?>
http://php.net/manual/en/function.fsockopen.php
fsockopen — Open Internet or Unix domain socket connection The socket
will by default be opened in blocking mode. You can switch it to
non-blocking mode by using stream_set_blocking(). The function
stream_socket_client() is similar but provides a richer set of
options, including non-blocking connection and the ability to provide
a stream context.
Since fsockopen will either connect or not connect (timeout) then that tells you whether or not a connection is available ("open") or being blocked (firewall, etc).
// Ping by website domain name, IP address or Hostname
function example_pingDomain($domain){
$starttime = microtime(true);
$file = #fsockopen($domain, 80, $errno, $errstr, 10);
$stoptime = microtime(true);
$status = 0;
if (!$file) {
$status = -1; // Site is down
} else {
fclose($file);
$status = ($stoptime - $starttime) * 1000;
$status = floor($status);
}
return $status;
}
If you really want to know if the FTP server is working or not, your best option is to actually send FTP commands through to it.
An FTP server, upon connect, should typically reply with the first three bytes "220" or "120". 220 is a "greeting". You can read more in RFC 959.
To be completely sure, you might be better off using ftp:// handling in PHP, e.g. actually authenticating a user (maybe user authentication is broken, but it's still able to send a greeting - does that count is "down"?)
Anyway, if you want better than "was I able to connect on that port?" or "did the connect succeed in a timely fashion?", you have to delve into actual communication over the socket. Ultimately, this means you have to do something special for each type of service (for some, read bytes, for others write bytes, etc.)
I have a device with relays connected to my network. I am able to connect to device via the built in url host to turn on and off the relays. What I would like to do is be able to send commands to the device turning on and off the relays either via php, vb code or make my own ASP url's for each relay that will do that same thing. I am using Visual Studio 2013.
I have the IP of the device and the port number.
I need to send it a 6 byte command: example
0xFD,Ox2,020,1,0,0x5d
This command will tell Relay 1 to turn on.
0xFD,Ox2,020,1,1,0x5d
This command will tell Relay 1 to turn off.
Any help with this would be greatly appreciated Thank you!
I think you may want to check out fsockopen
You can do something like:
$socket = fsockopen($ip, $port);
if($socket) {
fwrite($socket, $string);
}
Instead of building an ASP web site just to turn on/off the device, you can simply create a very simple HTML page with 2 buttons (ON and OFF). If you put this page on the network, it can be opened by any browser.
Assuming that your command string is processed as an URL, the Javascript functions executed when clicking on a button would call the following procedure:
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false );
xmlHttp.send( null );
return xmlHttp.responseText;
}
If the device is controlled by TCP/IP, you may need to code some C# functions, unless using a utility allowing to send data to TCP/IP (example "Packet sender").
I'm sure you've seen the "the connection was reset" message displayed when trying to browse web pages. (The text is from Firefox, other browsers differ.)
I need to generate that message/error/condition on demand, to test workarounds.
So, how do I generate that condition programmatically? (How to generate a TCP RST from PHP -- or one of the other web-app languages?)
Caveats and Conditions:
It cannot be a general IP block. The test client must still be able to see the test server when not triggering the condition.
Ideally, it would be done at the web-application level (Python, PHP, Coldfusion, Javascript, etc.). Access to routers is problematic. Access to Apache config is a pain.
Ideally, it would be triggered by fetching a specific web-page.
Bonus if it works on a standard, commercial web host.
Update:
Sending RST is not enough to cause this condition. See my partial answer, below.
I've a solution that works on a local machine, Now need to get it working on a remote host.
I would recommend doing this via a custom socket via CLI as messing with the apache process could be messy:
#!/usr/bin/php -q
<?php
set_time_limit (0);
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, '1.1.1.1', 8081) or die('Could not bind to address');
socket_listen($sock);
$client = socket_accept($sock);
sleep(1);
$pid = getmypid();
exec("kill -9 $pid");
?>
This will generate the desired error in Firefox as the connection is closed before read.
If you feel insanely daring, you could throw this into a web script but I wouldn't even venture trying that unless you own the box and know what you're doing admin wise.
I believe you need to close the low-level socket fairly abruptly. You won't be able to do it from Javascript. For the other languages you'll generally need to get a handle on the underlying socket object and close() it manually.
I also doubt you can do this through Apache since it is Apache and not your application holding the socket. At best your efforts are likely to generate a HTTP 500 error which is not what you're after.
Update:
This script worked well enough to test our connection-reset workaround, so it's a partial answer.
If someone comes up with the full solution that works on a remote host, I'll gladly mark that as the answer.
The following script works every time when running and tested on the same machine. But when running on a remote host, the browser gets the following last 3 packets:
Source Dest Protocol Info
<server> <client> TCP 8081 > 1835 [RST] Seq=2 Len=0
<server> <client> TCP 8081 > 1835 [RST] Seq=2 Len=0
<server> <client> TCP http > 1834 [ACK] Seq=34 Ack=1 Win=6756 Len=0
As you can see, the RST flag is set and sent. But Firefox fails silently with a blank page -- no messages of any kind.
Script:
<?php
$time_lim = 30;
$listen_port = 8081;
echo
'<h1>Testing generation of a connection reset condition.</h1>
<p><a target="_blank" href="http://' .$_SERVER["HTTP_HOST"]. ':' .$listen_port. '/">
Click here to load page that gets reset. You have ' . $time_lim . ' seconds.</a>
</p>
'
;
flush ();
?>
<?php
//-- Warning! If the script blocks, below, this is not counted against the time limit.
set_time_limit ($time_lim);
$socket = #socket_create_listen ($listen_port);
if (!$socket) {
print "Failed to create socket!\n";
exit;
}
socket_set_nonblock ($socket); //-- Needed, or else script executes until a client interacts with the socket.
while (true) {
//-- Use # to suppress warnings. Exception handling didn't work.
$client = #socket_accept ($socket);
if ($client)
break;
}
/*--- If l_onoff is non-zero and l_linger is zero, all the unsent data will be
discarded and RST (reset) is sent to the peer in the case of a connection-
oriented socket.
*/
$linger = array ('l_linger' => 0, 'l_onoff' => 1);
socket_set_option ($socket, SOL_SOCKET, SO_LINGER, $linger);
//--- If we just close, the Browser gets the RST flag but fails silently (completely blank).
socket_close ($socket);
echo "<p>Done.</p>";
?>