Нечетная проблема InetAddress.isReachable()
Моя работа заключается в разработке программного обеспечения для сетевых камер для розничной торговли. Одной из разновидностей программного обеспечения, которую разрабатывает моя команда, является веб-сервер, который извлекает различные отчеты, сгенерированные в HTML самой камерой (которая имеет собственный встроенный веб-сервер) и сохраненные на камере. Наше программное обеспечение затем получит эти отчеты с камеры и сохранит их на центральном веб-сервере.
В то время как мы прекрасно подключаем IP-адреса камер к нашему программному обеспечению, я разрабатываю простой класс Java, который будет запрашивать сеть и определять местонахождение всех камер в сети.
Проблема, однако, в том, что, хотя он отлично работает на моем ПК и компьютере моего коллеги, когда мы пытаемся запустить его на реальном компьютере веб-сервера, на котором будет размещаться наше программное обеспечение... он работает, но говорит, что каждый IP в подсети отключен / недостижимо, КРОМЕ IP шлюза.
Например, если я запускаю его со своего ПК или компьютера коллеги, когда он подключен к закрытой локальной сети, я получаю следующие активные IP-адреса вместе с флагом, указывающим, является ли это камерой или нет. (шлюз 192.168.0.1, маска подсети 255.255.255.0, что означает полный диапазон из 256 устройств, которые нужно искать)
IP:/192.168.0.1 Active:true Camera:false
IP:/192.168.0.100 Active:true Camera:true <- this is camera 1
IP:/192.168.0.101 Active:true Camera:true <- this is camera 2
IP:/192.168.0.103 Active:true Camera:false <- my PC
IP:/192.168.0.104 Active:true Camera:false <- this is our webserver
Но по какой-то причине при запуске той же программы с ПК веб-сервера, использующей ту же JRE, я обнаружил только следующее
IP:/192.168.0.1 Active:true Camera:false
Теперь мой код вместо того, чтобы перечислять каждый IP по порядку в главном потоке, вместо этого создает отдельный поток для каждого проверяемого IP и запускает их одновременно (в противном случае для перечисления всего диапазона IP-адресов потребуется чуть более 21 минуты). тайм-аут 5000 мс / IP). Затем основной поток повторно запускает эти потоки сканирования IP каждые 15 секунд снова и снова.
Я проверил, что все потоки на всех ПК работают до конца, никаких исключений не выдается. Даже проверил, что ни один из потоков не застревает. Каждый поток занимает от 5001 до 5050 мс от начала до завершения, и те потоки, которые имеют активный IP-адрес, заканчивают раньше (>5000 мс), поэтому я знаю, что он правильно ожидает полные 5000 мс в методе ipAddr.isReachable(5000).
Я и мой коллега в настоящий момент в замешательстве, хотя кажется, что эти активные IP-адреса нормально работают при работе на наших ПК, но не получают ответа от ПК веб-сервера???
Мы исключили проблемы с брандмауэром, проблемы с доступом администратора и т. Д. Единственное отличие состоит в том, что наш веб-сервер - это Embedded Win XP, а наши ПК - Windows 7.
Это поставило нас в тупик. Есть идеи почему?
Ниже приведен код, который запускает каждый поток IP:
public void CheckIP() {
new Thread() {
@Override
public void run() {
try {
isActive = ipAddr.isReachable(5000);
if (isActive) {
if (!isCamera) {
isCamera = new IpHttpManager().GetResponse(ipAddr.toString());
}
} else {
isCamera = false;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
РЕДАКТИРОВАТЬ: Вот код, который создает каждый IP для проверки после определения диапазона на основе шлюза и подсети...
for(int i=subMin; i<=subMax; i++) {
byte[] ip = new byte[] {(byte)oct[0],(byte)oct[1],(byte)oct[2],(byte)i};
try {
scanners[subCount] = new IpScan(InetAddress.getByAddress(ip));
subCount++;
} catch (UnknownHostException e) {
e.printStackTrace();
}}
2 ответа
Спасибо всем, но я так и не понял, почему эта странность произошла. Все, что я проверял, не было причиной, поэтому этот вопрос можно закрыть.
В любом случае, я полностью обошел все вокруг. Вместо того, чтобы использовать InetAddress, я просто перешел на родной язык и вместо этого создал свой собственный класс ping ICMP через JNA, вызывая библиотеки Windows IPHLPAPI.DLL и WSOCK32.DLL. Вот что я использовал...
public interface InetAddr extends StdCallLibrary {
InetAddr INSTANCE = (InetAddr)
Native.loadLibrary("wsock32.dll", InetAddr.class);
ULONG inet_addr(String cp); //in_addr creator. Creates the in_addr C struct used below
}
public interface IcmpEcho extends StdCallLibrary {
IcmpEcho INSTANCE = (IcmpEcho)
Native.loadLibrary("iphlpapi.dll", IcmpEcho.class);
int IcmpSendEcho(
HANDLE IcmpHandle, //Handle to the ICMP
ULONG DestinationAddress, //Destination address, in the form of an in_addr C Struct defaulted to ULONG
Pointer RequestData, //Pointer to the buffer where my Message to be sent is
short RequestSize, //size of the above buffer. sizeof(Message)
byte[] RequestOptions, //OPTIONAL!! Can set this to NULL
Pointer ReplyBuffer, //Pointer to the buffer where the replied echo is written to
int ReplySize, //size of the above buffer. Normally its set to the sizeof(ICMP_ECHO_REPLY), but arbitrarily set it to 256 bytes
int Timeout); //time, as int, for timeout
HANDLE IcmpCreateFile(); //win32 ICMP Handle creator
boolean IcmpCloseHandle(HANDLE IcmpHandle); //win32 ICMP Handle destroyer
}
А затем с помощью них, чтобы создать следующий метод...
public void SendReply(String ipAddress) {
final IcmpEcho icmpecho = IcmpEcho.INSTANCE;
final InetAddr inetAddr = InetAddr.INSTANCE;
HANDLE icmpHandle = icmpecho.IcmpCreateFile();
byte[] message = new String("thisIsMyMessage!".toCharArray()).getBytes();
Memory messageData = new Memory(32); //In C/C++ this would be: void *messageData = (void*) malloc(message.length);
messageData.write(0, message, 0, message.length); //but ignored the length and set it to 32 bytes instead for now
Pointer requestData = messageData;
Pointer replyBuffer = new Memory(256);
replyBuffer.clear(256);
// HERE IS THE NATIVE CALL!!
reply = icmpecho.IcmpSendEcho(icmpHandle,
inetAddr.inet_addr(ipAddress),
requestData,
(short) 32,
null,
replyBuffer,
256,
timeout);
// NATIVE CALL DONE, CHECK REPLY!!
icmpecho.IcmpCloseHandle(icmpHandle);
}
public boolean IsReachable () {
return (reply > 0);
}
Я предполагаю, что ваша логика итерации для определения другого IP-адреса основана на другой конфигурации, поэтому ваш компьютер выбирает все адреса, а ваш веб-сервер - нет.
Попробуйте добавить отладку в логику, где вы создаете список IP-адресов для проверки.