【发布时间】: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 数据包之前,这就是幕后发生的事情:
- PHP 发送一个数据包告诉 Java 服务器进行身份验证并给它一个令牌
- Java 服务器检查令牌并告诉 PHP 服务器它是否有效(如果是后者则断开连接)
- 然后 PHP 将包含用户名和哈希密码的数据包发送到 Java 服务器
- Java 服务器检查信息是否有效,如果有效则返回令牌
- 最后 PHP 发送数据包来验证令牌
- 如果令牌有效,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 上运行。我还发布了一个答案,描述了我如何解决我的问题