0

我正在尝试用 Java 编写 BOOTP 客户端/服务器,RFC 中的规范之一是客户端可以编写它想要连接的服务器的昵称。如果数据包到达的服务器不是指定的服务器,它应该丢弃引导请求。

我有三个类(BOOTPClient、BOOTPServer 和 BOOTPMessage)。到目前为止,我已经成功地将引导请求从客户端发送到服务器,服务器接收并开始处理它。

问题在这里:

String sname = new String(btpmsg.getSname());
String serverName = args[0];
boolean discard = false;
System.out.println("|"+serverName+"|"+sname+"|");
if (!sname.equalsIgnoreCase("") && !sname.equalsIgnoreCase(serverName)) {
    discard = true;
    System.out.println("The request was not for this server. Server requested: "+sname);
}

这意味着:如果字符串不为空(在这种情况下,我们不关心它到达哪个服务器),请确保它是正确的服务器。如您所见,我在“|”之间打印了两个字符串 100% 确保没有空格或任何可能混淆比较的东西。然而,它进入 if 块并执行里面的句子。如果字符串与服务器名称相同且为空,则会发生这种情况。

澄清一下:btpmsg 是 BOOTPMsg 类的一个实例,服务器名称存储为一个字节数组(所有内容都使用 ByteArrayOutputStream 编码成一个字节数组,以便与 DatagramPacket 一起发送),然后转换为字符串。我不知道问题可能出在哪里。

输出示例:

服务器(用“java BOOTPServer bootpserver”调用):

Server bootpserver running. Awaiting requests.
Bootrequest received.
|bootpserver|bootpserver|
The request was not for this server. Server requested: bootpserver

客户:

Enter your IP if known. Otherwise, press enter.

Enter the IP of the server if known. Otherwise, press enter.

Enter the name of the server if known. Otherwise, press enter.
bootpserver
Enter the file name if known. Otherwise, press enter.

我会很感激任何帮助,因为我不知道我还能寻找什么错误。我最好的选择是在 ByteArrayOutputStream 上使用“write”方法或在 DataInputStream 中使用 readFully,但所有其他参数都可以正常工作。提前非常感谢。

4

1 回答 1

1

你的getSname()方法返回一个固定长度的 64,这是BOOTP 协议byte[]中字段的指定长度。sname当您将它直接传递给String(byte[])构造函数时,您会得到一个用零字符填充到长度为 64 的字符串。

要解决此问题,您需要找到数组中的第一个零字节并在构造字符串时使用它。另外确保你传入一个明确的字符编码;否则,您将受到平台默认值的摆布。

因此,使用如下代码:

sname2string(byte[] sname) {
   int length = 0;
   while (length < 64 && sname[length] != 0) length++;
   return new String(sname, 0, length, StandardCharsets.ISO_8859_1);
}
于 2014-10-26T11:55:51.703 回答