speeding up fsockopen - php

I have a socket which connects to an irc server and sends some commands during the connection.
Seems like this:
$socket = #fsockopen(IRCIP, IRCPORT, $errno, $errstr, IMEOUT);
stream_set_timeout($socket, TIMEOUT);
fputs($socket, "SVSLIST\n");
But it takes a bit long (mostly, 0.5 second but sometimes its up to 1.5 second) Not to mention that both php script and the irc server works on the same machine.
So i would like to ask how can i speed up this process? I was using readfile with different kind of mechanism (building a httpd server as module in that irc server and redirect the readfile to do queries) to do that, it was pretty fast.. Is there a way to boost the speed?
Thanks.

The last parameter of fsockopen() is the timeout, set this to a low value to make the script complete faster, like this:
$socket = #fsockopen(IRCIP, IRCPORT, $errno, $errstr, 0.1);
Also... you have to know that this code:
$socket = fsockopen('www.mysite.com', 80);
Is way slower than:
$socket = fsockopen(gethostbyname('www.mysite.com'=, 80);
One last thing... if your script has to be run locally on the same machine of the IRC server, just use 127.0.0.1 to connect instead of the machine public IP address.

Related

Execute a PHP script only for fixed time

I have a function which creates a socket connection and listens on a port number for HL7 messages sent by a laboratory machine via TCP.
If the lab machine is not sending anything, my listen function keeps listening. Is there a way to specify that it should listen only for say 10 seconds and then if there are no messages, an error should be thrown?
$address = '0.0.0.0';
$port = 5600;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
$bind = socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);
$client = socket_accept($sock);
// Read the input from the client
$input = socket_read($client, 2024);
// Strip all white spaces from input
$segs = explode("|",$input);
// Close the master sockets
$close = socket_close($sock);
This is the solution:
socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>10,"usec"=>0)); // after 10 seconds socket will destroy the connection. Also you can set and uses
This looks like the XY problem.
That the thing you want to measure acts as a client rather implies that you might want to do more than just detect an open TCP connection in your script, e.g. capture some data. Further, the underlying OS has a lot of complex, well tested, reliable and tunable mechanisms for tracking the state of connections.
While you could do as stefo91 suggests and try to manipulate receive timeout, I'm not sure if this is applied in the wait for an initial connection. A better solution would be to set the socket to non-blocking. Don't forget to either:
inject some calls to sleep()/usleep() or
use socket_select()
unless you want your script to be burning a lot of resource with nothing to do.
But depending on a lot of information you've not told us about, the right solution might be to run one script as a server, and a second as a monitor. The second could be polling/parsing the output of netstat to check the connection.

strange socket timeout on Azure App Services, but works fine locally

I'm having weird issues with sockets. I'm trying to connect to this IP with the port 25565 to figure out the ping of this particular IP/Server. I have a piece of code that works just fine locally and shows me the ping without fail, it also works just fine on an OVH Kimsufi box running nginx/PHP CGI. Yet on Microsoft Azure it does not, showing me the 10060 (timeout) errorcode and this message: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.. And only for this one IP. Another IP (37.59.51.122) works just fine. I have this app running in 3 different regions, EU West, US West and US East. It works in none of them.
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
function ping($host, $port)
{
$time_start = round(microtime(true) * 1000);
$fp = fsockopen("tcp://" . $host, $port, $errno, $errstr, 1);
if ($fp) {
$time_end = round(microtime(true) * 1000);
fclose($fp);
$time = $time_end - $time_start;
return $time;
} else {
return $errno . ":" . $errstr;
}
}
echo ping("149.56.81.67", 25565);
Does anyone have any idea what could possibly be causing this problem? Is there an azure-specific setting I need to change to fix this?
Or is there an easy way to debug this on Azure?
I'm quite new to Azure so I'm very unfamiliar with it.
EDIT: I have tried in many different regions (from japan to west US.) and couldn't find any settings about firewalls or IP blacklists. I'm really at a loss here.
If you change your last line to ping 8.8.8.8 on port 53 (Google's Public DNS Servers), it does work as expected as you already pointed out.
However, from Kudu's DebugConsole (https://{appname}.scm.azurewebsites.net/DebugConsole), if i do a tcpping host:port i see either your remote firewall acting up or packet loss.
D:\home\site\wwwroot>tcpping 149.56.81.67:25565
Connection attempt failed: Connection timed out.
Connection attempt failed: Connection timed out.
Connected to 149.56.81.67:25565, time taken: 78ms
Connected to 149.56.81.67:25565, time taken: 86ms
Complete: 2/4 successfull attempts (50%). Average success time: 82ms
This is why you see the timeout.
Try to run tcpdump on your remote server to see if it's really packet loss or the machine is simply not sending a SYN back (may send a RST instead).
I have found out the problem. I had this script running in a loop, pinging it 5 times in quick succession. I have since added a 500ms delay between requests and I no longer have timeouts.
I wouldn't have figured this out without the help of evilSnobu. I figured out that tcpping.exe did work more often than my php script, despite the raw connection being virtually the same. The only difference was the delay between the requests. It was OVH's ddos protection firewall blocking my connections.

Limiting socket server access

This is security issue. I've got a socket server that should be accessed only from the same server, in other words, only from localhost. I need to somehow check if remote user that trying to connect is not an outsider. Currently I've come up with:
socket_getpeername($current_socket, $client_address, $client_port);
if( $client_address == '127.0.0.1' )
{
//allow
}
But such approach is not the best one, because I need to socket_accept() any user before proceeding. Does anybody know how to handle it?
Accepting the socket and then dropping the connection is totally acceptable.
If you don't like it, you can set up a firewall rule in your OS to allow connections only from localhost.
My suggestion is that you make your socket listen only to 127.0.0.1. This way it's only connectable from localhost.
I assume you are using stream_socket_server()
$socket = stream_socket_server("udp://127.0.0.1:1113", $errno, $errstr, STREAM_SERVER_BIND);
if (!$socket) {
die("$errstr ($errno)");
}

how to use php sockets to write string

So Im trying to get my head wrapped around this....
I open the port
$remip = $_SERVER['SERVER_ADDR']; //Grab my server address
$fp = fsockopen($remip, 80, $errno, $errstr, 10);//Godaddy hosting only 80 and 443 ports work
//fsockopen(ip address , port, IDK, IDK, timeout delay)
so now the ports open or if not maybe some error checking to be sure
if (!$fp) { echo "$errstr ($errno)<br>\n"; exit; } //Not sure what this echos out but its clear how it stops errors
So now that the port is open any ip/client can connect on this port????
Ill assume I can now connect....
So on my client I open a socket to my server ip address port tcp connection.....
The php file includes something like
else {$out = "hello, 80\r\n"; //out specifies the string to be written , bytes to write
fwrite($fp, $out); //$fp is the handle
fclose($fp)}//close the connection
at this point ill assume that my client gets the hello written to it ..
finish up by closing the connection
Im entirely new to this so Im attempting to understand some sample code here...
So how long is this socket open for? If i want to keep this port open do i need to do a cron job to launch this file periodically.
Im 100% sure that I have got something wrong here so please set me straight.
I think you have a misconception of what fsockopen does. In your example your fsockopen does not actually open port 80 (as in opening a server socket), but it opens a client socket that connects to port 80 on the server itself. It actually does open a (client) port which gets a (not completely) random number.
After you connected using fsockopen you can send HTTP commands to the webserver such as GET /index.php
What you need to use is socket_listen() and socket_bind(). There are a few places in the docs that show you how to get PHP listening on a socket: http://www.php.net/manual/en/function.socket-listen.php
I suggest you read and try them out by simply testing then with a unix tool called netcat (nc <ip_address> <port> command normally)

Is this the right way to connect to a socket? [duplicate]

The hosting service that I use currently does not let me use sockets, probably for good reason on their part. They do, however, let me use fsockopen. I was wondering what the difference is, because some scripts that worked with socket_create and even stream_socket_server, do not work with fsockopen. That said, if fsockopen should work, my code is listed below. What it does is it listens on its own ip address for incoming udp packets and reads them.
Thanks
$sock = fsockopen("udp://x.x.x.x", $port);
while(1)
{
$buf = fread($sock, 200);
flush();
ob_flush();
}
fsockopen creates a connection to a host, not a listening socket.
fsockopen($address) ~== socket_connect(socket_create(), $address)
Your hosting provider doesn't want you listening on alternate ports/protocols.
If what you have works, I wouldn't count on it always working as it would be a bug.

Categories