我的工作是为零售环境的网络摄像机开发软件.我的团队正在开发的软件之一就是Web服务器,它检索由相机本身(具有自己的嵌入式Web服务器)以HTML格式生成并存储在相机中的各种报告.然后,我们的软件将从摄像机获取这些报告,并将其存储在*Web服务器上.
在将摄像机的IP很好地插入到我们的软件中的同时,我正在开发一个简单的Java类,该类将查询网络并找到网络上的所有摄像机.
但是问题是,尽管它可以在我的PC和同事的PC上正常运行,但是当我们尝试在将托管我们软件的实际Web服务器PC上运行它时,它却在运行,但是说子网中的每个IP都处于脱机状态/网关IP不可访问.
例如,如果在插入封闭的LAN时从我的PC或同事PC上运行它,则会得到以下活动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从Web服务器PC运行相同的程序时,我只会得到以下内容
IP:/192.168.0.1 Active:true Camera:false
现在,我的代码不是在主线程上按顺序枚举每个IP,而是为要检查的每个IP创建一个单独的线程并同时运行它们(否则,枚举整个IP范围将花费大约21分钟的时间.超时时间为5000毫秒/ IP).然后,主线程每隔15秒钟反复运行这些IP扫描线程.
我检查了所有线程在所有PC上的运行是否都已完成,没有异常被抛出.甚至验证没有任何线程被卡住.每个线程从开始到完成大约需要5001到5050毫秒,而那些具有活动IP的线程会更快地完成(> 5000毫秒),因此我知道它在ipAddr.isReachable(5000)方法中正确等待了整整5000毫秒.
我和我的同事在这一点上感到很沮丧,虽然在我们的PC上运行时似乎可以达到那些活动IP的罚款,但是Web服务器PC却没有任何响应?
我们已经排除了防火墙问题,管理员访问问题等.唯一的区别是我们的Web服务器是Embedded Win XP,而我们的PC是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();
}}
解决方法:
谢谢大家,但我从未弄清楚或指出为什么发生这种奇怪情况.我检查的所有内容都不是原因,因此可以解决此问题.
无论如何,我最终完全解决了它.我没有使用InetAddress,而是直接使用JNA并通过Windows库IPHLPAPI.DLL和WSOCK32.DLL构建了自己的ICMP ping类.这是我用的…
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);
}