PHP Sockets - можно подключиться только с локального хоста (проблема переадресации портов?) - PullRequest
1 голос
/ 09 февраля 2011

Прежде всего, спасибо, что нашли время, чтобы прочитать это. У меня странная проблема с PHP-сокетами. Я работаю над демоном php socket, который работает через localhost, но когда я пытаюсь подключиться извне локальной сети или другого компьютера, он не работает. Я упростил моего демона до очень простого сокетного соединения, чтобы воспроизвести проблему, которую вы видите.

В основном, вот сенарио. Я запускаю демон сокета на своем сервере через порт 6667. Я могу подключиться к демону через telnet и из браузера на локальной машине, на которой запущен демон, но не могу с любой другой машины - демон даже не видит попытки подключения делается.

Чтобы еще больше усложнить проблему (именно поэтому я думаю, что это проблема переадресации портов), мой провайдер блокирует порт 80, поэтому я настроил dyndns и мой маршрутизатор на использование порта 8000. Я также настроил свой маршрутизатор для пересылки порт 6667 для моего сервера.

Чтобы получить доступ к моему демону из браузера, я ввожу следующий (seudo) URL:

http://mydomain.com:8000/client.php

Это работает с локальной машины и будет подключаться, но с любой другой машины демон даже не увидит попытки подключения. Однако, если я укажу порт следующим образом:

http://mydomain.com:6667

мой демон видит соединение, но, конечно, в браузер не загружена страница клиента, которую пользователь может использовать для взаимодействия с демоном.

Мой клиент использует флэш-файл для создания соединения с сокетом (jsocket), но я знаю, что это не файл междоменной политики, потому что политика правильная, и при подключении через localhost он правильно обслуживает файл политики.

Вот упрощенный код демона:

 <? 

// 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); 
?>

Резюме:

Я МОГУ подключиться с локального хоста через telnet и браузер ... Я МОГУ подключиться с других машин через telnet, но НЕ МОГУ подключиться с браузера с других машин, используя ip или имя домена, если указан порт 8000. Демон не видит попыток подключения. Если я укажу порт 6667, то демон увидит попытку подключения, но это бесполезно для пользователя. (

Любая помощь в этом вопросе будет принята с благодарностью! Спасибо!

Ответы [ 2 ]

8 голосов
/ 09 февраля 2011

Вы связываете сокет (используя socket_bind ) с localhost .Если в localhost есть PHP, связывающий сокет с 127.0.0.1 .

socket_bind, который используется для привязки сокета к определенному интерфейсу.Например:

socket_bind($socket, '127.0.0.1', 80);

Это позволяет подключаться к 127.0.0.1: 80 , но не к 192.168.1.100: 80 , даже если они одинаковымашина.Сокет привязан только к интерфейсу 127.0.0.1 :

$ 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

Если вы хотите привязать сокет ко всем доступным интерфейсам, используйте:

socket_bind($socket, '0.0.0.0', 80);

Тогда это работает:

$ 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.
2 голосов
/ 29 октября 2012

Я использую этот файл «port_forwarding.php» на сервере, чтобы открыть порт 3000 и перенаправить подключение удаленного клиента MySQL к файлу сокета Unix / порту 3306 сервера MySQL:

<?
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;
    }
?>
...