您的位置:首页 > 移动开发 > Android开发

Android扫描局域网内IP并建立Socket连接,和PC服务端收发数据

2017-04-06 12:04 751 查看
一、主要步骤

1.扫描局域网内所有IP

2.将扫描到的所有IP遍历建立连接

3.和服务端进行收发数据

二、扫描局域网内所有IP

这里直接用了http://blog.csdn.net/crazy_zihao/article/details/50523719这篇博客提供的一个工具类。

import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import android.text.TextUtils;
import android.util.Log;

/**
* @ClassName:ScanDeviceTool
* @Description:TODO<局域网扫描设备工具类>
* @author:zihao
* @date:2015年9月10日 下午3:36:40
* @version:v1.0
*/
public class ScanDeviceTool {

private static final String TAG = ScanDeviceTool.class.getSimpleName();

/** 核心池大小 **/
private static final int CORE_POOL_SIZE = 1;
/** 线程池最大线程数 **/
private static final int MAX_IMUM_POOL_SIZE = 255;

private String mDevAddress;// 本机IP地址-完整
private String mLocAddress;// 局域网IP地址头,如:192.168.1.
private Runtime mRun = Runtime.getRuntime();// 获取当前运行环境,来执行ping,相当于windows的cmd
private Process mProcess = null;// 进程
private String mPing = "ping -c 1 -w 3 ";// 其中 -c 1为发送的次数,-w 表示发送后等待响应的时间
private List<String> mIpList = new ArrayList<String>();// ping成功的IP地址
private ThreadPoolExecutor mExecutor;// 线程池对象

/**
* TODO<扫描局域网内ip,找到对应服务器>
*
* @return void
*/
public List<String> scan() {
mDevAddress = getHostIP();// 获取本机IP地址
mLocAddress = getLocAddrIndex(mDevAddress);// 获取本地ip前缀
Log.d(TAG, "开始扫描设备,本机Ip为:" + mDevAddress);

if (TextUtils.isEmpty(mLocAddress)) {
Log.e(TAG, "扫描失败,请检查wifi网络");
return null;
}

/**
* 1.核心池大小 2.线程池最大线程数 3.表示线程没有任务执行时最多保持多久时间会终止
* 4.参数keepAliveTime的时间单位,有7种取值,当前为毫秒
* 5.一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响
* ,一般来说,这里的阻塞队列有以下几种选择:
*/
mExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_IMUM_POOL_SIZE,
2000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(
CORE_POOL_SIZE));

// 新建线程池
for (int i = 1; i < 255; i++) {// 创建256个线程分别去ping
final int lastAddress = i;// 存放ip最后一位地址 1-255

Runnable run = new Runnable() {

@Override
public void run() {
// TODO Auto-generated method stub
String ping = ScanDeviceTool.this.mPing + mLocAddress
+ lastAddress;
String currnetIp = mLocAddress + lastAddress;
if (mDevAddress.equals(currnetIp)) // 如果与本机IP地址相同,跳过
return;

try {
mProcess = mRun.exec(ping);

int result = mProcess.waitFor();
Log.d(TAG, "正在扫描的IP地址为:" + currnetIp + "返回值为:" + result);
if (result == 0) {
Log.d(TAG, "扫描成功,Ip地址为:" + currnetIp);
mIpList.add(currnetIp);
} else {
// 扫描失败
Log.d(TAG, "扫描失败");
}
} catch (Exception e) {
Log.e(TAG, "扫描异常" + e.toString());
} finally {
if (mProcess != null)
mProcess.destroy();
}
}
};

mExecutor.execute(run);
}

mExecutor.shutdown();

while (true) {
try {
if (mExecutor.isTerminated()) {// 扫描结束,开始验证
Log.d(TAG, "扫描结束,总共成功扫描到" + mIpList.size() + "个设备.");
return mIpList;
}
} catch (Exception e) {
// TODO: handle exception
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/**
* TODO<销毁正在执行的线程池>
*
* @return void
*/
public void destory() {
if (mExecutor != null) {
mExecutor.shutdownNow();
}
}

/**
* TODO<获取本地ip地址>
*
* @return String
*/
private String getLocAddress() {
String ipaddress = "";

try {
Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces();
// 遍历所用的网络接口
while (en.hasMoreElements()) {
NetworkInterface networks = en.nextElement();
// 得到每一个网络接口绑定的所有ip
Enumeration<InetAddress> address = networks.getInetAddresses();
// 遍历每一个接口绑定的所有ip
while (address.hasMoreElements()) {
InetAddress ip = address.nextElement();
if (!ip.isLoopbackAddress()
&& (ip instanceof Inet4Address)) {
ipaddress = ip.getHostAddress();
}
}
}
} catch (SocketException e) {
Log.e("", "获取本地ip地址失败");
e.printStackTrace();
}

Log.i(TAG, "本机IP:" + ipaddress);
return ipaddress;
}
/**
* 获取ip地址
* @return
*/
public static String getHostIP() {

String hostIp = null;
try {
Enumeration nis = NetworkInterface.getNetworkInterfaces();
InetAddress ia = null;
while (nis.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) nis.nextElement();
Enumeration<InetAddress> ias = ni.getInetAddresses();
while (ias.hasMoreElements()) {
ia = ias.nextElement();
if (ia instanceof Inet6Address) {
continue;// skip ipv6
}
String ip = ia.getHostAddress();
if (!"127.0.0.1".equals(ip)) {
hostIp = ia.getHostAddress();
break;
}
}
}
} catch (SocketException e) {
Log.i("yao", "SocketException");
e.printStackTrace();
}
return hostIp;

}
/**
* TODO<获取本机IP前缀>
*
* @param devAddress
*            // 本机IP地址
* @return String
*/
private String getLocAddrIndex(String devAddress) {
if (!devAddress.equals("")) {
return devAddress.substring(0, devAddress.lastIndexOf(".") + 1);
}
return null;
}

}


这里需要注意的是,有时候有些明明存在的IP却扫描不到(也就是PING不通)。我遇到的是因为ICMP的回显没开,解决办法如下:控制面板–>系统和安全–>windows防火墙–>高级设置–>入站规则–>文件和打印机共享,选择启用。



三、和扫描到的IP遍历建立连接

/**
* 扫描局域网IP并连接
* @return 返回值表示是否连接成功
*/
private boolean getServerIP() {
new Thread(){
@Override
public void run() {
ScanDeviceTool scanDeviceTool = new ScanDeviceTool();
pList = scanDeviceTool.scan();//调用工具类方法开始扫描

if(pList != null && pList.size() >0) {
for (final String ip : pList) {
new Thread() {
@Override
public void run() {
try {
HOST = InetAddress.getByName(ip);
Log.d(TAG, "-------->" + ip);
} catch (UnknownHostException e) {
e.printStackTrace();
}
try {
socket = new Socket(HOST, PORT);
} catch (IOException e) {
e.printStackTrace();
}
if (socket != null) {//如果无法建立连接,socket将为空
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
e.printStackTrace();
}
if(socket.isConnected()){
Log.d(TAG, "-------->conncted: "+ip);
isConnected = true;
}
}

}
}.start();
}

}
}
}.start();
return isConnected;
}


四、和服务端进行收发数据

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_scan://开始扫描并建立连接
boolean result = getServerIP();
if(result){
Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(MainActivity.this,"连接失败",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_get://从服务端获取数据
if(isConnected) {
new Thread() {
@Override
public void run() {
while (true) {
if (!socket.isClosed()) {
if (socket.isConnected()) {
if (!socket.isInputShutdown()) {
try {
if ((content = in.readLine()) != null) {
content += "\n";
mHandler.sendMessage(mHandler.obtainMessage());
} else {
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}.start();
}else{
Toast.makeText(MainActivity.this,"还未连接到PC",Toast.LENGTH_SHORT).show();
}
break;
case R.id.btn_send://发送数据到服务端
if(isConnected) {
String msg = ed_msg.getText().toString();
if (socket != null) {
if (socket.isConnected()) {
if (!socket.isOutputShutdown()) {
out.println(msg);
ed_msg.setText("");
}
}
}
}else{
Toast.makeText(MainActivity.this,"还未连接到PC",Toast.LENGTH_SHORT).show();
}
break;
}
}


附件:服务端可执行exe程序

http://download.csdn.net/download/u013121097/9805019

另:Android端在读取数据(in.readLine())时,读取到’\n’或’\t’才算结束读取,如果没有读取到这两个符号就会一直阻塞。所以服务端的程序中,要在发送给客户端程序的数据末尾追加一个换行符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息