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

8
背景:我正在编写一个简单的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:Invalid argument。
根据此文档,空参数是正确的:
链接
引用如下:

public void bind(SocketAddress localAddr)
自API级别1开始
将此套接字绑定到localAddr指定的本地地址和端口。如果该值为null,则使用有效本地地址上的任何空闲端口
但是,不信任文档,我决定像这样枚举我的设备上的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地址,但是在bind()调用上我仍然会遇到完全相同的异常。有没有人能看出我可能错过了什么?我将继续研究并希望发布解决自己问题的方案,但我希望有人能为我提供捷径。

端口号?它是否在有效范围内? - Prince John Wesley
尝试使用不同的端口号。 - Prince John Wesley
2个回答

9

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

我找到了问题所在。似乎是我声明DatagramSocket的方式引起了问题。如果我使用DatagramChannel以以下方式打开DatagramSocket,则bind()调用将成功。

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

3
新建DatagramSocket对象,参数为null。 - Volodymyr Lykhonis

3
我也遇到了这个问题,并找到了原因:如果您调用无参数的构造函数 new DatagramSocket(),则会创建“一个UDP数据报套接字,该套接字绑定到本地主机上任何可用的端口并使用通配符地址”(根据API文档)。这实际上意味着套接字已经被绑定。我针对此问题提出的“解决方案”如下:
        SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
        DatagramSocket serverSocket = new DatagramSocket(null);
        serverSocket.bind(socketAddress);

通过使用 DatagramSocket(SocketAddress localAddr) 构造函数,可以明确创建一个未绑定的 Socket,从而使绑定 Socket 成为可能。

这可能比创建不必要的通道更加优雅。

P.S.: 有趣的是,这就是 DatagramSocket 与 TCP ServerSocket 的区别所在:后者的无参构造函数将创建一个未绑定的 ServerSocket,不会触发此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接