PHP <-> Java Socket 随机空包 [已解决]
Posted
技术标签:
【中文标题】PHP <-> Java Socket 随机空包 [已解决]【英文标题】:PHP <-> Java Socket random empty packet 【发布时间】: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 上运行。我还发布了一个答案,描述了我如何解决我的问题
【参考方案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->socket, $length, PHP_NORMAL_READ);
替换为 $line = socket_read($this->socket, $length, PHP_BINARY_READ);
完全解决了这个问题。
我也取消了 out.flush() 的注释,但我不确定这是否有任何区别。
再次感谢 markspace,帮助我解决这个问题!
【讨论】:
以上是关于PHP <-> Java Socket 随机空包 [已解决]的主要内容,如果未能解决你的问题,请参考以下文章