【问题标题】:socket_accept seems to hang on the first connectionsocket_accept 似乎挂在第一个连接上
【发布时间】:2012-08-14 08:11:42
【问题描述】:

我正在尝试在端口 8195 上创建一个简单的侦听器。当我在 PHP CLI 条件下尝试以下代码块时,它只显示一次“测试”,然后挂起。如果我删除文件“votifier.run”,该文件设计为开/关开关,它仍然会继续挂起。它从不显示“客户端已连接”。

此外,如果我在脚本运行时尝试在端口 8195 上通过 Telnet 连接到主机,我只会收到连接失败消息。就好像它正在寻找一种联系而不是放弃。

// Set the IP and port to listen to
$address = 'localhost';
$port = 8195;

// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
// Bind the socket to an address/port
socket_bind($sock, $address, $port);
// Start listening for connections
socket_listen($sock);

// Loop continuously
while ( file_exists('votifier.run') ) {
    echo 'Test';
    $client = socket_accept($sock);
    if( $client ) {
            echo 'Client connected';
            // Don't hang on slow connections
            socket_set_timeout($client, 5);

            // Send them our version
            socket_write("VOTIFIER MCWEBLINK\n");

            // Read the 256 byte block
            $block = socket_read($client, 256);
            ...

答案: socket_accept() 通常会挂起,直到建立连接。如果进行了连接尝试,脚本将继续,但由于套接字是在 localhost 上创建的,因此它只接受 来自 localhost 的连接。

解决方法是使用您的外部 IP 而不是“localhost”或“127.0.0.1”。然后你就可以 Telnet 到它了。

【问题讨论】:

  • 尝试将 6 (tcp) 作为协议传递给 socket_create

标签: php sockets


【解决方案1】:

我只是在这里猜测,但您尝试绑定的地址可能不是主机名吗?

如果套接字属于 AF_INET 系列,则地址是点分四进制表示法的 IP(例如 127.0.0.1)。

编辑

好的,我已使用您的脚本并尝试重现您的错误,但无法重现。它有几个缺陷,但没有一个会导致 telnet 客户端的连接尝试失败。

由于上述都不适用,让我们一一检查清单:

  • sockets 模块已加载/编译
  • localhost 确实解析为 127.0.0.1
  • 该端口未被任何其他正在运行的应用程序占用
  • 没有任何类型的防火墙规则会阻止 telnet 客户端和服务器之间的通信
  • 允许您连接的机器连接到服务器主机(如果不是,请尝试同一主机)
  • 在 while 循环中检查的文件确实存在
  • 您确定脚本中没有其他致命错误会阻止您发布的 sn-p 运行

这些都是我能想到的所有可能的错误来源,atm。尝试先修复小缺陷,然后检查清单。

if( $client ) {
    echo 'Client connected';
    // Don't hang on slow connections
    socket_set_option(
        $client,
        SOL_SOCKET,
        SO_RCVTIMEO | SO_SNDTIMEO,
        array('sec' => 5, 'usec' => 0)
    );

    // Send them our version
    socket_write($client, "VOTIFIER MCWEBLINK\n");
                 ^^^^^^^

    // Read the 256 byte block
    $block = socket_read($client, 256);

【讨论】:

  • 我确实注意到了这一点,并用 127.0.0.1 进行了尝试;虽然无济于事。结果相同。
  • 你检查过端口当前是否在使用吗?
  • 没有错误。 socket_last_error 的值在 socket_accept 之前是 Success,之后什么都没有,因为它挂在 socket_accept 上。
  • 谢谢,原来 socket_accept() 会挂起,直到进行连接尝试。当我尝试 Telnet-ing 时,它没有通过 - 可能是因为防火墙 - 所以脚本永远不会继续。我在另一个 PHP 脚本中尝试了一个简单的 fsockopen 和 fgets 并得到了我正在寻找的响应。
  • 这不是防火墙问题。必须使用外部 IP 63.***.***.226 而不是 127.0.0.1 创建套接字现在我可以 Telnet!
【解决方案2】:

您应该使用线程。如果客户端从不发送任何内容,您的代码将在 read() 方法中阻塞。每个接受的套接字都应该在一个新线程中完全处理。

【讨论】:

  • 如果客户端不发送任何内容,则套接字将在 5 秒后超时。
【解决方案3】:

您可能需要检查以下内容: PHP Votifier example for Minecraft Topsites

它解释了代码是如何工作的,它是进行加密、填充 256 个空格并发送数据包的基本功能。您可以对它进行一些工作,因为您可能想要改进它。

您可以在此处查看该插件的运行 php 的现场演示:http://topg.org/test_votifier

【讨论】:

  • 欢迎来到 Stack Overflow!感谢您发布您的答案!请务必仔细阅读FAQ on Self-Promotion。另请注意,每次链接到自己的网站/产品时,都要求发布免责声明。
猜你喜欢
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-20
  • 2015-08-26
  • 1970-01-01
  • 2019-06-09
相关资源
最近更新 更多