PHP <-> Java 套接字随机空包

PHP <-> Java Socket random empty packet

我正在开展一个项目,该项目需要 PHP 网络应用程序通过 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 服务器检查信息是否有效,如果是 returns 令牌
  5. 最后PHP发送数据包来验证令牌
  6. 如果令牌有效,Java 服务器发回 1,否则返回 200

令牌验证 (5) 之前的每个步骤都正常。

A var_dump 结果始终显示 string(0) ""

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

但是如果执行第 3 步和第 4 步读取数据包两次(因此使用 $response = $this->readPacket() 两次)确实有效并正确读取数字。 尽管不执行步骤 3 和 4 时读取两次会使 Java 服务器挂起。

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

感谢 markspace 的

我也解决了我的问题

他们建议尝试将 out.println() 替换为 out.print(),我已经尝试过,但不幸的是,除了 PHP 挂起之外什么也没有。

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

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

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