在局域网中通过端口号扫描服务器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                 // 遍历每一个接口绑定的所有ip
11                 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             @Override
15             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                    }catch(Exception e) {
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         @Override
17         public void onSeekIp(String ip) {
18             Log.e("UDP", "demo server_ip:"+ip);
19             
20         }
21     }
22 }

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

 

转载于:https://www.cnblogs.com/yishuifenglan/p/4164273.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值