Android:java.net.DatagramSocket.bind:无效参数异常

发布于 2024-10-22 08:12:10 字数 1578 浏览 4 评论 0原文

背景:我正在编写一个简单的 UDP 应用程序来 ping 一个测试版服务器,我每分钟左右管理一次,告诉我它仍在运行(对于那些想知道的人,我无法在服务器上启用 ping)。我计划在手机上运行此命令,以便在服务器不再响应时向我发出警告。

我正在尝试使用看似简单的 java.net.DatagramSocket :

    try
    {
        socket = new DatagramSocket();
        socket.bind(null);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

让我也说一下,我已经通过 android 清单启用了 Internet 权限,如果我删除使用子句来执行此操作,我会收到权限错误,因此我确信一切正常。当我将此代码下载到 Android 虚拟设备 (AVD) 并执行它时,在调用 bind() 时,出现以下异常:

03-17 19:07:39.401: INFO/System.out(338): java .net.BindException:无效参数

根据 在这个文档中,空参数是正确的:

公共无效绑定(SocketAddress localAddr)

自:API 级别 1

将此套接字绑定到 localAddr 指定的本地地址和端口。 如果该值为空,则使用有效本地地址上的任何空闲端口

但由于不信任文档,我决定像这样枚举设备上的 IP 地址:

    ArrayList<NetworkInterface>  allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
    
    NetworkInterface eth = allInterfaces.get(0);
                
    InetSocketAddress addr = new InetSocketAddress(eth.getInetAddresses().nextElement(), port);
    
    try
    {
        socket = new DatagramSocket();
        socket.bind(addr);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

当我单步执行代码时,它工作得很好,我可以在 AVD 上看到两个 IP 地址,但我在绑定上得到了完全相同的异常( ) 称呼。有人看到我可能会错过什么吗?我将继续研究并希望发布解决我自己问题的方法,但我希望有人能够为我解决这个问题。

Background: I'm writing a simple UDP application to ping a beta server I manage every minute or so to tell me it is still up and running (I can't enable ping on the server for those that are wondering). I plan to run this on my phone to warn me when the server is no longer responding.

I'm trying to use the seemingly simple java.net.DatagramSocket as such:

    try
    {
        socket = new DatagramSocket();
        socket.bind(null);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

Let me also say that I have enabled the Internet permissions through the android manifest and if I remove the uses clause to do so, I get a permissions error so I'm sure that is working OK. When I download this code to an Android Virtual Device (AVD) and execute it, on the call to bind() I am presented with this exception:

03-17 19:07:39.401: INFO/System.out(338): java.net.BindException: Invalid argument

According to this documentation, the null argument is correct:

public void bind (SocketAddress localAddr)

Since: API Level 1

Binds this socket to the local address and port specified by localAddr. If this value is null any free port on a valid local address is used.

But not trusting documentation, I decided to enumerate the IP addresses on my device like this:

    ArrayList<NetworkInterface>  allInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
    
    NetworkInterface eth = allInterfaces.get(0);
                
    InetSocketAddress addr = new InetSocketAddress(eth.getInetAddresses().nextElement(), port);
    
    try
    {
        socket = new DatagramSocket();
        socket.bind(addr);
    } 
    catch (SocketException e)
    {
        System.out.println(e.toString());
        throw e;
    }

When I step through the code, it works great and I can see the two IP address on the AVD but I get the exact same exception on the bind() call. Does anybody out there see what i might be missing? I will continue to research and hopefully post a solution to my own problem, but I am hoping somebody out there will be able to shortcut this for me.

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

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

发布评论

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

评论(2

祁梦 2024-10-29 08:12:10

[编辑:如果您看到我之前的回复,我犯了一个经典的调试错误,在一个测试中更改了两个变量,而另一个测试解决了我的问题。]

我发现了问题。这是我声明 DatagramSocket 的方式似乎会导致问题。如果我使用 DatagramChannel 按以下方式打开 DatagramSocket,则 bind() 调用成功。

      DatagramChannel channel = DatagramChannel.open();
      DatagramSocket socket = channel.socket();

[Edited: if you saw my previous response I made the classic debugging mistake of changing two variable in one test and it was the other one that solved my problem.]

I found the problem. It is the way I'm declaring the DatagramSocket that appears to cause problems. If I use a DatagramChannel to open the DatagramSocket in the following way then the bind() call is successful.

      DatagramChannel channel = DatagramChannel.open();
      DatagramSocket socket = channel.socket();
素手挽清风 2024-10-29 08:12:10

我也偶然发现了这个问题,并找到了原因:如果您调用无参数构造函数new DatagramSocket(),这将创建“一个 UDP 数据报套接字绑定到任何可用端口< /strong> 在本地主机上使用通配符地址”(根据 API 文档)。所以这实际上意味着,Socket 已经绑定了。我对此的“修复”如下:

        SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
        DatagramSocket serverSocket = new DatagramSocket(null);
        serverSocket.bind(socketAddress);

这显式创建了一个未绑定的 Socket(通过 DatagramSocket (SocketAddress localAddr) 构造函数),从而可以依次绑定 Socket。

这可能是比创建不必要的通道更优雅的解决方案。

PS:奇怪的是,这就是 DatagramSocket 与 TCP ServerSocket 的不同之处:后者的无参数构造函数将创建一个未绑定的 ServerSocket,而不会触发此问题。

I've stumbled across this problem either and have found the cause: if you call the parameterless constructor new DatagramSocket(), this creates "a UDP datagram socket which is bound to any available port on the local host using a wildcard address" (as per the API docs). So this actually means, the Socket is already bound. My "fix" for this is as follows:

        SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
        DatagramSocket serverSocket = new DatagramSocket(null);
        serverSocket.bind(socketAddress);

This explicitly creates an unbound Socket (through the DatagramSocket (SocketAddress localAddr) constructor), making it possible to bind the Socket in turn.

This is probably the more elegant solution than creating an unnecessary channel.

P.S.: Strangely enough, this is where DatagramSocket differs from a TCP ServerSocket: the parameterless constructor of the latter will create an unbound ServerSocket, not triggering this problem.

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