getSocketAddress()方法导致延迟,导致Android中的通信延迟

时间:2012-01-27 18:17:48

标签: android udp

我正在开发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

2 个答案:

答案 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秒。