我正在开发UDP响应器来处理基本的SSDP命令。这段代码的目的是进行自动发现,因此当服务器向特定组发送多播时,所有其他订阅设备都应该向发送多播的主机和端口发回一个UDP数据包,告知其存在。我的Android设备收到并发送数据包就好了但是因为从getSocketAddress()方法返回SocketAddress对象需要太长时间服务器超时,关闭监听端口并且永远不会从Android设备返回数据包。
这是我的代码:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MulticastSocket ms = null;
byte[] packBuf = new byte[128];
try {
ms = new MulticastSocket(32410);
ms.joinGroup(InetAddress.getByName("239.255.255.250"));
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
while (true)
{
DatagramPacket receivedPack = new DatagramPacket(packBuf, packBuf.length);
try {
ms.receive(receivedPack);
Log.d(TAG, "Received data");
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
String responseStr = "HTTP/1.0 200 OK\n" +
"Content-Type: app\n" +
"Resource-Identifier: 945e7dd5913ab45f1db4f271a1620b9471fb7d4d\n" +
"Name: Test App\n" +
"Port: 8888\n" +
"Updated-At: 1319511680\n" +
"Version: 0.9.3.4-29679ad\n" +
"Content-Length: 23\n\n" +
"<message>test</message>";
byte[] response = responseStr.getBytes();
DatagramSocket sendSocket = null;
try {
sendSocket = new DatagramSocket();
} catch (IOException e2) {
// TODO Auto-generated catch block
Log.e(TAG,"Erro",e2);
}
DatagramPacket outPack;
try {
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
sendSocket.send(outPack);
} catch (UnknownHostException e1) {
Log.e(TAG,"Erro",e1);
}
catch (IOException e) {
Log.e(TAG,"Erro",e);
}
catch (Exception e)
{
Log.e(TAG,"Erro",e);
}
}
}
有什么想法吗?
提前感谢,
FBR
答案 0 :(得分:1)
最可能的问题是getSocketAddress()
正在尝试解析IP地址的DNS名称,该名称由于是多播地址或只是一般的DNS延迟而超时。
InetSocketAddress
类有一个构造函数选项needResolved
,可以控制此行为。不幸的是,似乎DatagramPacket.getSocketAddress()
不允许您指定您希望该设置为false。
这显然是一个已知问题,最近有一些讨论: Issue 12328: DatagramChannel - cannot receive without a hostname lookup
该帖子暗示这已在Android 3.0中得到修复,并为Android 2.0提供了一些可能会或可能不起作用的解决方法。
在您的情况下,您可以尝试创建InetSocketAddress
设置为INADDR_ANY并将端口0设置为needsResolved
,然后在创建receivedPack
时将其传递给。希望receive()
将重复使用并记住设置。
答案 1 :(得分:0)
有两件事情浮现在脑海中......
1)当你改变时会发生什么:
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());
到
outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getAddress(), receivedPack.getPort());
2)我记得家庭自动化系统中存在嵌入式Java的这类问题。我们的短期解决方案是将大部分机器和多播地址放在hosts文件中。从长远来看,我们最终得到了一台本地DNS服务器。
Java网络堆栈中的某个地方有一个参数,告诉它在内存中缓存DNS故障的时间。我认为,这个数字可以达到5分钟,而不是10秒。