首页 > 代码库 > 在局域网中通过端口号扫描服务器IP

在局域网中通过端口号扫描服务器IP

     简要说明                                                                                                                                                                                                                                                                                                                      

      本人才接触Android不就,这个月有个任务是这样的。客户端要和服务器进行Socket通信,由于服务器不固定也就导致了服务器IP不固定,就不能实现于多个服务器通信,于是有了这样一个需求。客户端根据服务器提供的端口号来扫描服务器IP,从而满足这个需求。拿到需求一看,果断不会,于是就百度去了。搜索解雇倒是不少,可是打开一看全是重复的代码,复制——粘贴。仔细一看,就连我这个新手也看出来了很多问题,果断拿来大大修改了一番,废话不多少直接看代码吧:

 

   实现代码:

 1     //本地IP 2     private String locAddress; 3     //核心线程数 4     private  int corePoolSize = 2; 5     //最大线程数 6     private  int maximumPoolSize = 5; 7     //线程池维护线程所允许的空闲时间 8     private  long keepAliveTime = 30; 9     //线程池维护线程所允许的空闲时间的单位10     private  TimeUnit unit = TimeUnit.SECONDS;1112     //线程池所使用的缓冲队列13     private  BlockingQueue<Runnable> workQueue = new LinkedBlockingDeque<Runnable>();14     @SuppressWarnings("unused")15     private  ThreadPoolExecutor threadPoolExecutor 16     = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);

从这段代码可以看出,我主要是定义了一个线程池,之后要开启线程来扫描局域网IP的,百度的方法是直接开启255个线程,我对这种做法真不知道说什么了~~~不多说,直接看方法代码:

 

  

 1      2           public  void scan(final int SERVERPORT){ 3             locAddress = getLocAddrIndex();//获取本地ip前缀 4            5           //开启线程 6             threadPoolExecutor.execute( new connectionServer(SERVERPORT, locAddress,0,100)); 7             threadPoolExecutor.execute( new connectionServer(SERVERPORT, locAddress,101,200)); 8             threadPoolExecutor.execute( new connectionServer(SERVERPORT, locAddress,201,256)); 9             threadPoolExecutor.shutdownNow();10          11           }12     

  从这个方法是用于外部调用的scan方法,传递端口号,然后开启线程进行扫描,大家都知道,如果在一个局域网的话设备的网段是一样的,比如说:一台电脑和手机都连接了同一个wifi。那么电脑的IP就可能是192.168.8.X,手机IP就是192.168.8.Y。就是说前三个字段是一致的,那我们只要去适配最后一位,那手机就一定有几率来匹配到电脑。这样一来就简单了,最后一位无非就是1~255所以我把这个字段分开来,开启三个线程分别扫描。扫描方法之后会列出来,我们先看看怎么得到局域网前三个字段,也就是举例中的192.168.8

getLocAddrIndex()

方法是获得IP前缀的

 1         /** 2          * @return 3          * 获取IP前缀 4          */ 5            6         private String getLocAddrIndex() { 7              String str = getLocAddress(); 8                  9                 if(!str.equals("")){10                   return str.substring(0,str.lastIndexOf(".")+1);11                 }12             return null;13         }

可以看到,这个方法只是将getLocAddress()方法获得的本地IP进行了截取,也就是截取出网段。下来放出如何获取本地IP:

 1     public static String getLocAddress() { 2             String ipaddress = ""; 3             try { 4               Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); 5               // 遍历所用的网络接口 6               while (en.hasMoreElements()) { 7                 NetworkInterface networks = en.nextElement(); 8                 // 得到每一个网络接口绑定的所有ip 9                 Enumeration<InetAddress> address = networks.getInetAddresses();10                 // 遍历每一个接口绑定的所有ip11                 while (address.hasMoreElements()) {12                   InetAddress ip = address.nextElement();13                   if (!ip.isLoopbackAddress()14                       && InetAddressUtils.isIPv4Address(ip.getHostAddress())) {15                       ipaddress = ip.getHostAddress();16                     17                   }18                 }19               }20             } catch (SocketException e) {21              22               e.printStackTrace();23             }24            25              26             return ipaddress;27         }

这个方法是百度找的,可以获取到设备的IP但是别忘记权限哦。到这里我们也就获取到了网段地址也就是我们所说的192.168.8

接下来放出线程扫描端口的方法:

 1         public  class connectionServer extends Thread{ 2             private int sERVERPORT;//端口号 3             private String slocAddress;//网段 4             private int sNum;//开始扫描点 5             private int eNum;//结束扫描点 6             public  connectionServer(int SERVERPORT, String locAddress,int startNum,int endNum) { 7                 sERVERPORT = SERVERPORT; 8                 slocAddress = locAddress; 9                 sNum = startNum;10                 eNum = endNum;11                  12             }13     14             @Override15             public void run() {16                 for(int i = sNum;i < eNum; i ++){17                     18                     String current_ip = slocAddress+i;19                     if(Call(current_ip, sERVERPORT)){20                         onSeekIp(current_ip);21                         22                     }23                     24                 }  25                 26             }27 } 

可以看出来是用了一个构造将需要的参数传递进来。然后在run()方法里用for循环进来匹配 ,关于匹配的方法我要说几句,第一次我用的是命令行匹配的方法也就是- p - l  也就是先用了下Window DOS下的ping命令能平通的再尝试和服务器连接。可是后来发现有好多设备无法执行这个命令,比如 鄙人用的小米手机可以,同事的魅族就无法执行了,找来找去发现socket就有一个判断端口是否打开的方法,正式踏破铁屑无觅处,得来全不费工夫啊,各位看官,请看代码:

 1         //判断端口是否打开 2           public  boolean Call(String ip, int port) { 3                4                 try { 5                     Socket socket = new Socket(); 6                     socket.connect(new InetSocketAddress(ip, port), 15); 7                     socket.close(); 8                     return true; 9                     10                     return false;11                 }12 13             }

connect这个方法,没错就是这个方法可以判断端口是否打开,后面我用了阻塞连接,timeout设置了15如果连接不上就返回fasle一旦连接上了就返回true,在线程里面可以看到返回true就调用了一个onSeepIP的方法,这个是什么了,其实这个是写了一个供外部访问的接口,已经和这个需求没有多大关系了。另外在附上调取的Demo,如果能帮到大家就再好不过了。

 1      2     public void setOnSeekListener(OnSeekIpListener listener){ 3         this.listener = listener; 4     } 5      6     private void onSeekIp(String ip){ 7         if( listener != null){ 8             listener.onSeekIp(ip); 9         }10     };

这些还是写在这个类里面的,OnSeekIPListener 是从新定义了一个接口类,里面只有一个简单的方法:

1 public interface OnSeekIpListener {2 3     public void onSeekIp(String ip);4 5 }

到这里这个可供外部调用的的 寻找服务器IP的需求已经完成了。下来些一个简单的Demo来调用接口:

 1 public class MainActivity extends Activity { 2      3     String date ; 4     @Override 5     protected void onCreate(Bundle savedInstanceState) { 6         // TODO Auto-generated method stub 7      8         super.onCreate(savedInstanceState); 9         UDPClient udpClient = new UDPClient();10         udpClient.setOnSeekListener(new UDPSeekListenner());11         udpClient.scan(6666);12     }13 14     class UDPSeekListenner implements OnSeekIpListener {15 16         @Override17         public void onSeekIp(String ip) {18             Log.e("UDP", "demo server_ip:"+ip);19             20         }21     }22 }

至此,所有流程已经完毕,还请各位大大轻喷。

 

在局域网中通过端口号扫描服务器IP