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
数据包之前幕后发生的事情:
- PHP 发送一个数据包告诉 Java 服务器进行身份验证并给它一个令牌
- Java 服务器检查令牌并告诉 PHP 服务器它是否有效(如果有效则断开连接)
- PHP 然后将包含用户名和散列密码的数据包发送到 Java 服务器
- Java 服务器检查信息是否有效,如果是 returns 令牌
- 最后PHP发送数据包来验证令牌
- 如果令牌有效,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 帮我解决这个问题!
我正在开展一个项目,该项目需要 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
数据包之前幕后发生的事情:
- PHP 发送一个数据包告诉 Java 服务器进行身份验证并给它一个令牌
- Java 服务器检查令牌并告诉 PHP 服务器它是否有效(如果有效则断开连接)
- PHP 然后将包含用户名和散列密码的数据包发送到 Java 服务器
- Java 服务器检查信息是否有效,如果是 returns 令牌
- 最后PHP发送数据包来验证令牌
- 如果令牌有效,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 帮我解决这个问题!