我正在编写代码,以便从我的移动设备发送UDP Multicast
Wifi
。在网络中的其他设备上运行服务器代码。服务器将监听多播,以其IP地址和系统类型进行响应(类型:计算机,移动设备,Raspberry Pi,Flyport等)。
在已发送UDP Multicast
的移动设备上,我需要设置设备列表以响应UDP Multicast
。
为此,我创建了一个类,它将作为device details
的结构。
DeviceDetails.class
public class DeviceDetails
{
String DeviceType;
String IPAddr;
public DeviceDetails(String type, String IP)
{
this.DeviceType=type;
this.IPAddr=IP;
}
}
我正在group address of 225.4.5.6
和Port Number 5432
发送UDP多播数据包。
我创建了一个会调用thread
的课程,该课程会发送UDP Packets
。另一方面,我创建了一个receiver thread
来实现 Callable 接口,以返回响应的设备列表。
以下是代码:
MulticastReceiver.java
public class MulticastReceiver implements Callable<DeviceDetails>
{
DatagramSocket socket = null;
DatagramPacket inPacket = null;
boolean check = true;
public MulticastReceiver()
{
try
{
socket = new DatagramSocket(5500);
}
catch(Exception ioe)
{
System.out.println(ioe);
}
}
@Override
public DeviceDetails call() throws Exception
{
// TODO Auto-generated method stub
try
{
byte[] inBuf = new byte[WifiConstants.DGRAM_LEN];
//System.out.println("Listening");
inPacket = new DatagramPacket(inBuf, inBuf.length);
if(check)
{
socket.receive(inPacket);
}
String msg = new String(inBuf, 0, inPacket.getLength());
Log.v("Received: ","From :" + inPacket.getAddress() + " Msg : " + msg);
DeviceDetails device = getDeviceFromString(msg);
Thread.sleep(100);
return device;
}
catch(Exception e)
{
Log.v("Receiving Error: ",e.toString());
return null;
}
}
public DeviceDetails getDeviceFromString(String str)
{
String type;
String IP;
type=str.substring(0,str.indexOf('`'));
str = str.substring(str.indexOf('`')+1);
IP=str;
DeviceDetails device = new DeviceDetails(type,IP);
return device;
}
}
以下代码是调用Receiver Thread
:
public class DeviceManagerWindow extends Activity
{
public void searchDevice(View view)
{
sendMulticast = new Thread(new MultiCastThread());
sendMulticast.start();
ExecutorService executorService = Executors.newFixedThreadPool(1);
List<Future<DeviceDetails>> deviceList = new ArrayList<Future<DeviceDetails>>();
Callable<DeviceDetails> device = new MulticastReceiver();
Future<DeviceDetails> submit = executorService.submit(device);
deviceList.add(submit);
DeviceDetails[] devices = new DeviceDetails[deviceList.size()];
int i=0;
for(Future<DeviceDetails> future :deviceList)
{
try
{
devices[i] = future.get();
}
catch(Exception e)
{
Log.v("future Exception: ",e.toString());
}
}
}
}
现在接收数据包的标准方法是在无限循环下调用receive method
。但是我希望仅在前30秒接收传入连接,然后停止寻找连接。
This is similar to that of a bluetooth searching. It stops after 1 minute of search.
问题在于,我可以使用计数器,但问题是 thread.stop
现在已被删除。不仅如此,如果我将 receive method
置于无限循环下,它将永远不会返回该值。
我该怎么办?我想搜索30秒,然后停止搜索,并希望返回响应的设备列表。
答案 0 :(得分:2)
您应该致电stop()
,而不是致电interrupt()
。这会导致InterruptedException
在您的代码的可中断位置被抛出,例如在调用Thread.sleep()
时或在被I / O操作阻止时。很遗憾,DatagramSocket
未实现InterruptibleChannel
,因此无法中断对receive
的调用。
因此,您要么使用DatagramChannel
而不是DatagramSocket
,那么receive()
会在调用ClosedByInterruptException
时抛出Thread.interrupt()
。或者您需要通过调用DatagramSocket.setSoTimeout()
来设置超时,从而导致receive()
在指定的时间间隔后抛出SocketTimeoutException
- 在这种情况下,您将不需要中断线程。
最简单的方法是简单地设置套接字超时:
public MulticastReceiver() {
try {
socket = new DatagramSocket(5500);
socket.setSoTimeout(30 * 1000);
} catch (Exception ioe) {
throw new RuntimeException(ioe);
}
}
这将导致socket.receive(inPacket);
在30秒后抛出SocketTimeoutException
。正如您已经抓住Exception
,这就是您需要做的一切。
这是一个更激进的重构。
public class MulticastReceiver implements Callable<DeviceDetails> {
private DatagramChannel channel;
public MulticastReceiver() {
try {
channel = DatagramChannel.open();
channel.socket().bind(new InetSocketAddress(5500));
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public DeviceDetails call() throws Exception {
ByteBuffer inBuf = ByteBuffer.allocate(WifiConstants.DGRAM_LEN);
SocketAddress socketAddress = channel.receive(inBuf);
String msg = new String(inBuf.array(), 0, inBuf.capacity());
Log.v("Received: ","From :" + socketAddress + " Msg : " + msg);
return getDeviceFromString(msg);;
}
}
DeviceManagerWindow
看起来有点不同;我不确定你打算在那里做什么,因为你在处理列表和数组,但是你只有一个未来......所以我假设你想要听30秒并获取尽可能多的设备。
ExecutorService executorService = Executors.newFixedThreadPool(1);
MulticastReceiver receiver = new MulticastReceiver();
List<DeviceDetails> devices = new ArrayList<DeviceDetails>();
long runUntil = System.currentTimeMillis() + 30 * 1000;
while (System.currentTimeMillis() < runUntil) {
Future<Object> future = executorService.submit(receiver);
try {
// wait no longer than the original 30s for a result
long timeout = runUntil - System.currentTimeMillis();
devices.add(future.get(timeout, TimeUnit.MILLISECONDS));
} catch (Exception e) {
Log.v("future Exception: ",e.toString());
}
}
// shutdown the executor service, interrupting the executed tasks
executorService.shutdownNow();
就是这样。无论您选择哪种解决方案,都不要忘记关闭插座/通道。
答案 1 :(得分:-1)
我已经解决了..您可以按照以下方式运行代码:
<强> DeviceManagerWindow.java 强>
public class DeviceManagerWindow extends Activity
{
public static Context con;
public static int rowCounter=0;
Thread sendMulticast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device_manager_window);
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null)
{
WifiManager.MulticastLock lock = wifi.createMulticastLock("WifiDevices");
lock.acquire();
}
TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
tb.removeAllViews();
con = getApplicationContext();
}
public void searchDevice(View view) throws IOException, InterruptedException
{
try
{
sendMulticast = new Thread(new MultiCastThread());
sendMulticast.start();
sendMulticast.join();
}
catch(Exception e)
{
Log.v("Exception in Sending:",e.toString());
}
这里是时间限制搜索....你可以使用 thread.join
退出你的主题 //Device Will only search for 1 minute
for(long stop=System.nanoTime()+TimeUnit.SECONDS.toNanos(1); stop>System.nanoTime();)
{
Thread recv = new Thread(new MulticastReceiver());
recv.start();
recv.join();
}
}
public static synchronized void addDevice(DeviceDetails device) throws InterruptedException
{
....
Prepare your desired list here.
....
}
}
不要在聆听方添加任何循环。只需使用socket.receive
<强> MulticastReceiver.java 强>
public class MulticastReceiver implements Runnable
{
DatagramSocket socket = null;
DatagramPacket inPacket = null;
public MulticastReceiver()
{
try
{
socket = new DatagramSocket(WifiConstants.PORT_NO_RECV);
}
catch(Exception ioe)
{
System.out.println(ioe);
}
}
@Override
public void run()
{
byte[] inBuf = new byte[WifiConstants.DGRAM_LEN];
//System.out.println("Listening");
inPacket = new DatagramPacket(inBuf, inBuf.length);
try
{
socket.setSoTimeout(3000)
socket.receive(inPacket);
String msg = new String(inBuf, 0, inPacket.getLength());
Log.v("Received: ","From :" + inPacket.getAddress() + " Msg : " + msg);
DeviceDetails device = getDeviceFromString(msg);
DeviceManagerWindow.addDevice(device);
socket.setSoTimeout(3000)
只会将套接字的侦听时间设置为3秒。如果数据包没有到达,它将更进一步。 DeviceManagerWindow.addDevice(device);
此行将调用调用类中的addDevice方法。您可以在哪里准备清单
}
catch(Exception e)
{
Log.v("Receiving Error: ",e.toString());
}
finally
{
socket.close();
}
}
public DeviceDetails getDeviceFromString(String str)
{
String type;
String IP;
type=str.substring(0,str.indexOf('`'));
str = str.substring(str.indexOf('`')+1);
IP=str;
DeviceDetails device = new DeviceDetails(type,IP);
return device;
}
}
希望有效..好吧它会起作用。 祝一切顺利。如果有任何问题,请告诉我。