【问题标题】:PHP <-> Java Socket random empty packetPHP <-> Java Socket 随机空包 [已解决]
【发布时间】:2021-10-14 08:46:33
【问题描述】:

我正在开发一个需要 PHP Web 应用程序通过 TCP 套接字访问 Java 服务器的项目。一切似乎都运行良好,除了一个小细节:如果采取特定步骤(在代码下方列出),总会有一个空包

我不确定原因是什么,这是我第一次让两种不同语言之间的套接字相互通信,也是第一次在 PHP 中使用它们,所以我的代码可能并不理想。

代码如下:

这些是PHP中发送和读取数据包的函数

function sendPacket($message) : void {
    if (!$this->connected && Config::get('debugging')) {
        echo("Cancelled packet send as we are not connected.");
        connectionFailed("There has been an error. Please, contact the administrators.");
    }
    socket_write($this->socket, $message."\nend\n") or
        connectionFailed("There has been an error. Please, contact the administrators.");
}

function readPacket($length = 15) : string {
    if(!$this->connected) {
        if (Config::get('debugging'))
            echo("Cancelled read as we are not connected.");
        connectionFailed("There has been an error. Please, contact the administrators.");
    }

    $line = socket_read($this->socket, $length, PHP_NORMAL_READ);
    if (substr($line, -1) === "\r")
        socket_read($this->socket, 1, PHP_BINARY_READ);

    if (str_ends_with($line, "\n"))
        $line = substr($line, 0, strlen($line) - 1);

    return $line;
}

然后我用它来向服务器发送令牌并检索响应

public function isUserTokenValid(string $userToken) : string {
    $this->sendPacket("user:validate-token:$userToken");
    usleep(500 * 1000); // I've tried to put this here in case it was a delay issue, but it wasn't
    $response = $this->readPacket();
    return $response;
}

这是我用来读取数据包的 Java 代码

private String readPacket() throws IOException {
    StringBuilder packet = new StringBuilder();
    String line = null;
    while ((line = in.readLine()) != null && !line.equals("end")) // in is a BufferedReader
        packet.append(line);

    return packet.toString();
}

这是我用来发送数据包的东西

private void sendPacket(String content) throws IOException {
    if ((!isConnected()) || out == null)
        return;

    System.out.println("OUT> " + content); // This is for debugging and proves that a value is being sent.
    out.println(content); // Out is a PrintStream
    out.flush(); // I've tried both flushing and not flushing, it doesn't change much
}

读取数据包后,我将其拆分然后解析。 在我发送user:validate-token:$userToken 数据包之前,这就是幕后发生的事情:

  1. PHP 发送一个数据包告诉 Java 服务器进行身份验证并给它一个令牌
  2. Java 服务器检查令牌并告诉 PHP 服务器它是否有效(如果是后者则断开连接)
  3. 然后 PHP 将包含用户名和哈希密码的数据包发送到 Java 服务器
  4. Java 服务器检查信息是否有效,如果有效则返回令牌
  5. 最后 PHP 发送数据包来验证令牌
  6. 如果令牌有效,Java 服务器返回 1,如果无效则返回 200

令牌验证 (5) 之前的每一步都很顺利。

不过,结果的 var_dump 始终显示 string(0) ""

跳过第 3 步和第 4 步会导致一切正常。

但是如果执行步骤 3 和 4 两次读取数据包(因此使用 $response = $this->readPacket() 两次)确实可以正常工作并正确读取数字。 虽然没有执行第 3 步和第 4 步时读取两次会使 Java 服务器挂起。

如果我不够清楚或需要更多代码,请告诉我

【问题讨论】:

  • 我不确定,但我注意到您在 Java 端使用 out.println()。这将在数​​据之后附加一个换行符,这可能会让你绊倒。您确定要在其中包含换行符吗?你能用out.print()试试看问题是否消失?
  • 是的,不幸的是我已经尝试了 out.print() 但是 PHP 服务器似乎不明白数据包已经收到 - 基本上它发送身份验证数据包,不承认它是收到一个数据包并且永远不会发送下一个 编辑:这是因为我使用的是 PHP_NORMAL_READ,它会一直读取到新行 (php.net/manual/en/function.socket-read.php)
  • Java 服务器的操作系统是什么?
  • 你带领我走向正确的道路。我将 PHP_NORMAL_READ 替换为 PHP_BINARY_READ(类似于 Java 的 InputStream#ready),并将 out.println() 替换为 out.print(),现在一切正常
  • 我已经解决了这个问题,但是 PHP 和 Java 都在 PHP 上运行。我还发布了一个答案,描述了我如何解决我的问题

标签: java php sockets tcp


【解决方案1】:

感谢 markspace 的 comment,我也解决了我的问题。

他们建议尝试将out.println() 替换为out.print(),我已经尝试过,但不幸的是,这只会导致PHP 挂起。

但是,更多地阅读 PHP 的 socket_read 的参数,我了解到 PHP_BINARY_READ(这也是默认模式)与 Java 的 InputStream.ready() 相同,基本上是读取直到它发现没有输入(实际上,这正是我所需要的),而 PHP_NORMAL_MODE 会一直读取,直到找到一个换行符(\r\n)。 因此,在 Java 中将 out.println() 替换为 out.print() 并在 PHP 中将 $line = socket_read($this-&gt;socket, $length, PHP_NORMAL_READ); 替换为 $line = socket_read($this-&gt;socket, $length, PHP_BINARY_READ); 完全解决了这个问题。

我也取消了 out.flush() 的注释,但我不确定这是否有任何区别。

再次感谢 markspace,帮助我解决这个问题!

【讨论】:

    猜你喜欢
    • 2011-03-27
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-24
    • 2012-04-30
    • 2011-04-05
    相关资源
    最近更新 更多