PHP Sockets - can only connect from localhost (Port Forwarding problem?) - php

First of all, thanks for taking the time to read this. I have a strange problem with PHP sockets. I working on a php socket daemon which works via localhost, but when I try to connect from outside the LAN or another PC, it doesn't work. I've simplified my daemon to a very basic socket connection to replicate the issue for you to see.
Basically, here's the senario. I start the socket daemon on my server on port 6667. I can connect to the daemon via telnet and from the browser on the local machine running the daemon, but I cannot from any other machine - the daemon doesn't even see a connection attempt being made.
To further complicate the issue (which is why I think it's a port forwarding issue), my ISP blocks port 80, so I've setup dyndns and my router to use port 8000. I've also setup my router to forward port 6667 to my server.
To access my daemon from a browser, I enter the following (seudo) url:
http://mydomain.com:8000/client.php
This works from the local machine and will connect, but from any other machine, the daemon doesn't even see a connection attempt being made. However, if I specify the port like this:
http://mydomain.com:6667
my daemon does see a connection being made, but of course then the browser doesn't have a client page loaded that the user can use to interact with the daemon.
My client uses a flash file to create the socket connection (jsocket), but I know it isn't the cross-domain policy file because the policy is correct, and when connecting via localhost, it serves the policy file correctly.
Here's the simplified daemon code:
<?
// set some variables
$host = '0.0.0.0';
$port = 6667;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
// echo input back
$output = $input . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>
Summary:
I CAN connect from localhost via telnet and browser... I CAN connect from other machines via telnet, but I CAN NOT connection from the browser from other machines using the ip or domain name when port 8000 is specified. The daemon doesn't see any connection attempt. If I specify port 6667, then the daemon see's a connection attempt, but that is useless to the user. :(
Any help in this matter would be greatly appreciated! Thanks!

You're binding the socket (using socket_bind) onto localhost. Supplying localhost there will have PHP bind the socket to the 127.0.0.1.
socket_bind is used to bind a socket to a specific interface. Per example:
socket_bind($socket, '127.0.0.1', 80);
This allows you to connect to 127.0.0.1:80, but not 192.168.1.100:80, even if they are the same machine. The socket is bound to the 127.0.0.1 interface only:
$ telnet localhost 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
$ telnet 192.168.1.100 80
Trying 192.168.1.100...
telnet: Unable to connect to remote host: Connection refused
If you want to bind the socket on all available interfaces, use:
socket_bind($socket, '0.0.0.0', 80);
Then this works:
$ telnet localhost 80
Trying 127.0.0.1...
Connected to 127.0.0.1.
$ telnet 192.168.1.100 80
Trying 192.168.1.100...
Connected to 192.168.1.100.

I use this "port_forwarding.php" on server to open port 3000 and forward remote mysql client connection to unix socket file / port 3306 of mysql server:
<?
set_time_limit(0);
function shutdown()
{global $ipsock, $rmsock;
if ($ipsock) fclose($ipsock);
if ($rmsock) fclose($rmsock);
}
register_shutdown_function('shutdown');
$target_socket='unix:///tmp/mysql.sock';//or 'tcp://192.168.0.2:3306'
$ipsock=stream_socket_server('tcp://192.168.0.2:3000', $errno2, $errstr2);
stream_set_blocking($ipsock, 0);
while (true)
{usleep(5000);//0.005s, to reduce cpu consumption
$c_ipsock=stream_socket_accept($ipsock); //even add '-1', it won't wait
$rmsock=stream_socket_client($target_socket, $errno, $errstr);
#stream_set_blocking($rmsock, 1);
while (($c_ipsock && !feof($c_ipsock)) && ($rmsock && !feof($rmsock)))
{$swrite=$except=null;
$sread=array($c_ipsock, $rmsock);
stream_select($sread, $swrite, $except, 5);
//print_r($sread);echo " \n";
if ($sread[0]===$rmsock)
{if ($data=fread($rmsock, 65536))
{//echo 'rmsock:'.strlen($data).' '.$data." \n";
myfwrite($c_ipsock, $data);
}
}
else if ($sread[0]===$c_ipsock)
{if ($data=fread($c_ipsock, 65536))
{//echo 'ipsock:'.strlen($data).' '.$data." \n";
myfwrite($rmsock, $data);
}
}
//var_export(array(feof($c_ipsock), feof($rmsock)));echo " \n";
}
#fclose($c_ipsock);
#fclose($rmsock);
}
function myfwrite($fd,$buf) {
$i=0;
while ($buf != "") {
$i=fwrite ($fd,$buf,strlen($buf));
if ($i==false) {
if (!feof($fd)) continue;
break;
}
$buf=substr($buf,$i);
}
return $i;
}
?>

Related

php - how to create a socket server in my webhost

I've a webhost and I want to create a socket connection with my application .
I've this code :
<?php
$host = "127.0.0.1";
$port = 25003;
// don't timeout!
set_time_limit(0);
if (!extension_loaded('sockets')) {
die('The sockets extension is not loaded.');
}
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
echo "Client Message : " . $input;
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>
when I run the page , it returns "Could not create socket"
I'm running the code on a share web service
what is the problem ? How can I fix it ?
I tried your code on my machine with XAMPP installed and is working, it actually does open that port, I tested with telnet through putty. Answering to your questions I think like #Jon Stirling said your hosting does not allow you to create a socket. That's why hosting companies sell web hostings packages and virtual private servers, if you want to bind a port you should look for a VPS.
I am sure you have solved this and moved jobs since you posted it but as someone who has just gone through this I would like to direct everyone who lands here to this page:
https://www.php.net/manual/en/function.socket-select.php
I was looking for a way to have a socket server that does not chew up CPU cycles and only does something when there is something to do. That solution blocks while it is waiting for connections to do something then it processes them.
Pay special attention to the comments about setting $tv_sec to null as this is the "Make Work" flag that prevents chewing up the CPU.
This allows one to create a socket server in PHP that does not chew up CPU and also processes multiple connections.
The only missing piece of the puzzle is disconnecting clients that do not disconnect themselves.
Unless there is a connection timeout that can be set I think the solution is to set $tv_sec to some suitable value, like 2 seconds, and then track the time a connection has been connected then disconnect it if it breaches some time. The downside to this is it will use CPU but if you unblock every 2 seconds then you can use that to process timeouts etc. Otherwise, you have to rely on clients disconnecting. That may not be an issue for you but in my particular usecase it is.

Host a PHP Socket server program in AWS

My requirement is to host a php socket server script in AWS EC2. and communicate to that socket server. This is what I have done so far but its not working.
server.php script that acts a socket server and listens to clients:
<?php
// set some variables
$host = "127.0.0.1";
$port = 53;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
echo "Client Message : ".$input;
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
In AWS security group, I have added following Inbound rule:
I run the server,php script from SSH using command "php server.php".
I tried to connect to the server from SocketTest tool where I entered following
value
host: 52.xx.xx.xxx (masked the actual value here) and port: 53
I am not able to connect to the socket server. It would be really helpful if someone can guide me if I am missing anything here
Please note that same server.php program is working fine when tested in local xampp server
You have used '127.0.0.1' as host in server script.
You have to replace it with your server's private IP address.

php socket connections

i'm trying to make a php tcp/ip server with the following code:
<?php
// set some variables
$host = "localhost";
$port = 3804;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socket\n");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listener\n");
// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connection\n");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read input\n");
// clean up input string
$input = trim($input);
// reverse client input and send back
$output = strrev($input) . "\n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write output\n");
// close sockets
socket_close($spawn);
socket_close($socket);
?>
i've randomly choose to work on the 3804 port and when i'm trying to telnet to my host on that port i'm not able to make a connection.. is there any more settings i need to make in the server that the php scripts hosted in, in order to allow my php script to listen to that port ?
Since you pass "localhost" as the second parameter of socket_bind, your socket will only listen to connections from the address localhost resolves to, typically 127.0.0.1. Set $host = '0.0.0.0'; to allow connections from everywhere.
You may also want to configure your firewall(s) to let through connections to port 3804.
That code works for me. Are you running this code from apache or another web server? Have you tried running those lines with php -a?

PHP: socket_connect is working, but not socket_bind

I am trying to connect via TCP Socket to a third party product. I am able to do so (and send a message successfully) with the following code:
if (isset($port) and ($socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) and (socket_connect($socket, $address , $port)))
{
$text="Connection successful on IP $address, port $port";
$data = "<msg id=1>text</msg>" . $newline;
socket_send($socket, $data, strlen($data), MSG_DONTROUTE);
$text .= socket_strerror(socket_last_error());
socket_close($socket);
}
The down side is that I also need to listen on this socket. As I understand it, I first need to bind, rather than using connect. When I run the code below, I get this error when calling socket_bind
Only one usage of each socket address (protocol/network address/port) is normally permitted.
code (snippet from a TCP Class, I have verified that the IP address, port, etc are the same in both snippets):
$this->Socket = socket_create(AF_INET, SOCK_STREAM, 0);
$result = socket_bind($this->Socket, $this->Host, $this->Port);
$result = socket_listen($this->Socket, 3) or die("Could not set up socket listener\n");
$spawn = socket_accept($this->Socket) or die("Could not accept incoming connection\n");
How is it that I can connect using socket_connect but not socket_bind? Is it correct that I need to use socket_bind if I want to listen on this socket?
I am running PHP on a Windows XP Apache installation (Zend). I should also mention that the only other application running when I try to execute this code is the third party program to which I am trying to connect.
Thank you for any insight.

PHP sockets problem

Hey guys, I am trying to do some socket programming in PHP.
So I am running a socket "server":
$address = '127.0.0.1';
$port = '9999';
$masterSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($masterSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($masterSocket, $address, $port);
socket_listen($masterSocket, 5);
$clientSocket = socket_accept($masterSocket);
So I open up SSH and run this script. It is running, no errors.
Then I have another PHP script which attempts to connect to this:
$fp = fsockopen("me.com", 9999, $errno, $errstr, 30);
fclose($fp);
but it's giving me:
Warning: fsockopen(): unable to connect to me.com:9999 (Connection refused)
How do I begin to fix this?
You haven't finished the listening socket sequence, you need to call socket_accept to accept new connections. There is an example in the comments in the PHP documentation.
$clients = array();
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,'127.0.0.1',$port);
socket_listen($socket);
socket_set_nonblock($socket);
while(true)
{
if(($newc = socket_accept($socket)) !== false)
{
echo "Client $newc has connected\n";
$clients[] = $newc;
}
}
http://php.net/manual/en/function.socket-accept.php
1) Check if the port is firewalled off. You could use telnet to check this.
2) See if it works when the client and server are on the same machine (I'm guessing from your mention of SSH that the server is remote).
3) If it works locally and you can hit the remote port using other tools then it's going to be tricky. I'd suggest you wail and gnash your teeth for a bit; I'm out of ideas.
EDIT: Heh. Or you could just read Steve-o's answer. Teeth-gnashing is still an option.
I know you said that "me.com" is an example but, just to be sure, socket_bind is expecting an IP address.
From http://php.net/manual/en/function.socket-bind.php :
address
If the socket is of the
AF_INET family, the address is an IP
in dotted-quad notation (e.g.
127.0.0.1).
If the socket is of the AF_UNIX
family, the address is the path of a
Unix-domain socket (e.g.
/tmp/my.sock).
I know the question is very old, but if someone still has this problem, make sure you connect to the SAME address you are listening on,
For example, If you're listening on 127.0.0.1 and your Machine address is me.com, you won't be able to connect to me.com with it, for that you'll have to listen on me.com.
Listening on: localhost:8088
Can only connect via: localhost:8088 // not via me.com:8088
Listening on: me.com:8088
Can only connect via: me.com:8088 // not via localhost:8088

Categories