getSocketAddress() 方法会导致延迟,从而导致 Android 中的通信滞后

发布于 2024-12-29 09:31:20 字数 2185 浏览 0 评论 0原文

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

I'm developing a UDP responder to handle basic SSDP commands. The purpose of this piece of code is to do auto discovery, so when the server sends a multicast to a specific group all other subscribed devices should send back a UDP packet announcing its presence to the host and port of who sent the multicast. My android device receives and sends the packet just fine but because it takes too long to get back the SocketAddress object from getSocketAddress() method the server times out, closes the listening port and never gets a packet back from the android device.

Here's my code:

    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);
        }
    }
}

Any ideas?

thanks in advance,

fbr

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

Spring初心 2025-01-05 09:31:20

最可能的问题是 getSocketAddress() 正在尝试解析 IP 地址的 DNS 名称,该 IP 地址由于是多播地址或只是一般 DNS 延迟而超时。

InetSocketAddress 类有一个构造函数选项 needResolved 可以控制此行为。不幸的是,DatagramPacket.getSocketAddress() 似乎不允许您指定希望将该值设置为 false。

这显然是一个已知问题,最近对此进行了一些讨论:
问题 12328:DatagramChannel - 在不查找主机名的情况下无法接收

表明这个问题已在 Android 3.0 中修复,并为 Android 2.0 提供了一些可能有效或无效的解决方法。

在您的情况下,您可以尝试创建一个设置为 INADDR_ANY 的 InetSocketAddress 和端口 0,并将 needsResolved 设置为 0,然后在创建 receivedPack 时将其传入代码>.希望 receive() 能够重用它并记住该设置。

The most likely problem is that getSocketAddress() is trying to resolve the DNS name of the IP address, which is timing out either due to it being a multicast address or just general DNS lag.

The InetSocketAddress class has a constructor option needResolved which can control this behavior. Unfortunately, it does not appear that DatagramPacket.getSocketAddress() allows you to specify that you want that set to false.

This is apparently a known issue, with some recent discussion of it here:
Issue 12328: DatagramChannel - cannot receive without a hostname lookup

The thread suggests that this has been fixed in Android 3.0, and offers a couple of workarounds for Android 2.0 which may or may not work.

In your case, you could try creating an InetSocketAddress set to INADDR_ANY and port 0 with needsResolved set to 0, and then pass that in when you create receivedPack. Hopefully receive() will reuse that and remember the setting.

羞稚 2025-01-05 09:31:20

我想到了 2 件事...

2)时会发生什么:

outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());

1) 当您更改为

outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getAddress(), receivedPack.getPort());

我记得在家庭自动化系统上的嵌入式 Java 中遇到过此类问题。我们的短期解决方案是将大部分机器和多播地址放入主机文件中。从长远来看,我们最终得到了本地 DNS 服务器。

Java 网络堆栈中的某处有一个参数,告诉它在内存中缓存 DNS 故障多长时间。我想,我们把这个数字从 10 秒提高到了 5 分钟。

2 things come to mind...

1) What happens when you change:

outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getSocketAddress());

to

outPack = new DatagramPacket(response, responseStr.length(), receivedPack.getAddress(), receivedPack.getPort());

2) I remember having this sort of problem with an embedded Java on a Home Automation system. Our short term solution was to put most of the machine and multicast addresses in the hosts file. Long term we ended up with a local DNS server.

There is a parameter somewhere in the Java Network stack that tells it how long to cache DNS failures in memory. We cranked that number up to, I think, 5 minutes instead of 10 seconds.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文