Equals возвращает false при сравнении одинаковых строк
Я пытаюсь написать BOOTP Client/Server на Java, и одна из спецификаций в 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.
Буду признателен за любую помощь, потому что я не знаю, что еще я могу искать ошибки. Лучше всего было использовать метод write для ByteArrayOutputStream или readFully в DataInputStream, но все остальные параметры работают нормально. Заранее большое спасибо.
1 ответ
Ваш getSname()
метод возвращает byte[]
фиксированной длины 64, которая является указанной длиной sname
поле в протоколе BOOTP. Когда вы передаете его непосредственно 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);
}