PHP 套接字 - 只能从本地主机连接(端口转发问题?)

发布于 2024-10-16 12:01:12 字数 1936 浏览 5 评论 0原文

首先,感谢您花时间阅读本文。我的 PHP 套接字有一个奇怪的问题。我正在开发一个通过本地主机工作的 php 套接字守护进程,但是当我尝试从 LAN 或另一台 PC 外部连接时,它不起作用。我已将我的守护进程简化为一个非常基本的套接字连接,以复制该问题供您查看。

基本上,这就是情况。我在服务器上的端口 6667 上启动套接字守护程序。我可以通过 telnet 并从运行守护程序的本地计算机上的浏览器连接到守护程序,但我不能从任何其他计算机连接到守护程序 - 守护程序甚至看不到连接尝试正在制作中。

为了使问题进一步复杂化(这就是为什么我认为这是端口转发问题),我的 ISP 阻止了端口 80,因此我设置了 dyndns 和我的路由器以使用端口 8000。我还设置了我的路由器以将端口 6667 转发到我的服务器。

要从浏览器访问我的守护程序,我输入以下(伪)url:

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

这在本地计算机上工作并将连接,但从任何其他计算机,守护程序甚至看不到正在进行的连接尝试。但是,如果我像这样指定端口:

http://mydomain.com:6667

我的守护程序确实看到正在建立连接,但是浏览器当然不会加载用户可以用来与守护程序交互的客户端页面。

我的客户端使用闪存文件创建套接字连接(jsocket),但我知道它不是跨域策略文件,因为策略是正确的,并且当通过本地主机连接时,它可以正确提供策略文件。

下面是简化的守护进程代码:

 <? 

// 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 从其他机器连接,但当端口 8000 处于连接状态时,我无法使用 ip 或域名从其他机器的浏览器连接指定的。守护进程没有看到任何连接尝试。如果我指定端口 6667,则守护程序会看到连接尝试,但这对用户来说毫无用处。 :(

任何有关此事的帮助将不胜感激!谢谢!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

究竟谁懂我的在乎 2024-10-23 12:01:12

您正在将套接字(使用 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.

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.
愁杀 2024-10-23 12:01:12

我在服务器上使用这个“port_forwarding.php”打开端口3000并将远程mysql客户端连接转发到mysql服务器的unix套接字文件/端口3306:

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

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;
    }
?>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文