同wifi环境下android设备自动获取socket服务端的ip地址和端口号的方法-UDP广播

一、最近做项目,需要使用socket做一个常连接,实现实时通信,但是需求是在同一个wifi环境下,ip地址是动态获取的,这样就造成了服务端地址的不确定性。解决这个问题的关键就是如何拿到服务端的Ip。我们可以这样想,服务端可以在获得ip以后通过一种方式把这个地址告诉客户端。这样我们就注意到UDP多点广播是一个好的解决方法。

要使用多点广播,需要让一个数据报标有一组目标主机地址,其思想是设置一组特殊网络地址作为多点广播地址,第一个多点广播地址都被看作是一个组,当客户端需要发送、接收广播信息时,加入该组就可以了。IP协议为多点广播提供这批特殊的IP地址,这些IP地址范围是224.0.0.0---239.255.255.255,其中224.0.0.0为系统自用。在java中需要用到MulticastSocket这个类。

其主要思路就是虚拟一个网络组,只要注册加入这个组的客户端都可以接收到广播者发送的数据。

1、创建一个MulticastSocket类,端口号自定义,但是每个接收者的端口号要与这个一致

mSocket = new MulticastSocket(BROADCAST_PORT);

2、虚拟一个多点广播地址,224.0.0.1--239.255.255.255任选。

address = InetAddress.getByName(BROADCAST_IP);

3、建立需要发送出去的数据,自定义的,xxxx是确认信息,还包括局域网ipsocket端口号,为建立socket做准备。

sendData = ("xxxx" + "-" + ip + "-" + port).getBytes();

3、创建一个DatagramPacket对象,包括需要发送的数据,广播地址和端口号

dataPacket = new DatagramPacket(sendDatasendData.lengthaddress,

BROADCAST_PORT);

4、将该MulticastSocket对象加入到指定的多点广播地址

mSocket.joinGroup(address);//加入广播接收组

5、设置广播生存时间0-255

mSocket.setTimeToLive(1);

6.  使用MulticastSocket对象的send方法 发送数据

mSocket.send(dataPacket);

7.  不接收广播的时候调用leaveGroup方法

 mSocket.leaveGroup(address);

8、接收端udp的创建过程与发送端基本一致

9、接收端使用mSocket.receive(dataPacket)接收数据,dataPacketDatagramPacket对象

 

因为我的项目中有一端是插电源的设备,所以我把耗电的这端作为服务端,然后每隔5秒向外发送一次广播,只要在同wifi环境下,客户端可以随时连接服务端。

二、代码

1、服务端代码UDPSocketBroadCast

private static final String BROADCAST_IP = "224.224.224.225";
private static final int BROADCAST_PORT = 8681;
private static byte[] sendData;
private boolean isStop = false;
private static UDPSocketBroadCast broadCast = new UDPSocketBroadCast();
private MulticastSocket mSocket = null;
private InetAddress address = null;
private DatagramPacket dataPacket;
private UDPSocketBroadCast() {
}
/**
 * 单例
 * 
 * @return
 */
public static UDPSocketBroadCast getInstance() {
  if (broadCast == null) {
    broadCast = new UDPSocketBroadCast();
  }
  return broadCast;
}
 
/**
 * 开始发送广播
 * 
 * @param ip
 */
public void startUDP(String ip, int port) {
sendData = ("xxxx" + "-" + ip + "-" + port).getBytes();
ShowLogManager.outputDebug("tag", ip+";"+port);
new Thread(UDPRunning).start();
}
 
/**
 * 停止广播
 */
public void stopUDP() {
isStop = true;
destroy();
}
 
/**
 * 销毁缓存的数据
 */
public void destroy() {
broadCast = null;
mSocket = null;
address = null;
dataPacket = null;
sendData = null;
}
 
/**
 * 创建udp数据
 */
private void CreateUDP() {
try {
mSocket = new MulticastSocket(BROADCAST_PORT);
mSocket.setTimeToLive(1);// 广播生存时间0-255
address = InetAddress.getByName(BROADCAST_IP);
mSocket.joinGroup(address);//加入广播接收组
dataPacket = new DatagramPacket(sendData, sendData.length, address,
BROADCAST_PORT);
} catch (IOException e) {
e.printStackTrace();
}
}
 
/**
 * 5秒发送一次广播
 */
private Runnable UDPRunning = new Runnable() {
 
@Override
public void run() {
while (!isStop) {
if (mSocket != null) {
try {
mSocket.send(dataPacket);
Thread.sleep(5 * 1000);// 发送一次停5秒
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
CreateUDP();
}
}
}
};


2、客户端代码

private final String BROADCAST_IP = "224.224.224.225";
private final int BROADCAST_PORT = 8681;
private byte[] getData = new byte[1024];
private boolean isStop = false;
private MulticastSocket mSocket = null;
private InetAddress address = null;
private DatagramPacket dataPacket;
private Thread mUDPThread = null;
private UDPDataCallBack mCallBack = null;
 
/**
 * 开始接收广播
 * 
 * @param ip
 */
public void startUDP(UDPDataCallBack mCallBack) {
this.mCallBack = mCallBack;
mUDPThread = new Thread(UDPRunning);
mUDPThread.start();
}
/**
 * 停止广播
 */
public void stopUDP() {
mSocket.leaveGroup(address);
isStop = true;
mUDPThread.interrupt();
}
 
/**
 * 创建udp数据
 */
private void CreateUDP() {
try {
mSocket = new MulticastSocket(BROADCAST_PORT);
mSocket.setTimeToLive(1);// 广播生存时间0-255
address = InetAddress.getByName(BROADCAST_IP);
mSocket.joinGroup(address);
dataPacket = new DatagramPacket(getData, getData.length, address,
BROADCAST_PORT);
Log.d("tag", "udp is create");
} catch (IOException e) {
e.printStackTrace();
}
}
 
private Runnable UDPRunning = new Runnable() {
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String result = (String) msg.obj;
mCallBack.mCallback(result);
Log.d("tag", "handler get data:" + result);
}
};
 
@Override
public void run() {
CreateUDP();
Message msg = handler.obtainMessage();
while (!isStop) {
if (mSocket != null) {
try {
mSocket.receive(dataPacket);
String mUDPData = new String(getData, 0,
dataPacket.getLength());
/**
 * 确定是否是这个客户端发过来的数据
 */
if (mUDPData != null
&& "xxxx".equals(mUDPData
.split("-")[0])) {
msg.obj = mUDPData;
handler.sendMessage(msg);
isStop = true;
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
msg.obj = "error";
handler.sendMessage(msg);
}
}
}
};
public interface UDPDataCallBack {
public void mCallback(String str);
}


客户端在接收到服务端发来的udp广播后会退出接收广播,然后启动另一个线程创建socket,所以我在代码中使用handler和回调方法,将接收到的广播信息传递给创建socket的方法。

参考:http://hunanliutian.blog.163.com/blog/static/950690762013102010358541/

展开阅读全文

没有更多推荐了,返回首页