背景:我正在编写一个简单的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权限,如果我删除uses子句这样做,我会收到权限错误,所以我确信它工作正常。当我将此代码下载到Android虚拟设备(AVD)并执行它时,在调用bind()时,我遇到了以下异常:
03-17 19:07:39.401:INFO / System.out(338):java.net.BindException:参数无效
根据this文档,null参数是正确的:
public void bind(SocketAddress localAddr)
自:API Level 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()调用上得到完全相同的异常。有没有人看到我可能会失踪的?我将继续研究并希望能够为我自己的问题发布一个解决方案,但我希望有人可以为我提供快捷方式。
答案 0 :(得分:9)
[编辑:如果你看到我之前的回复,我在一次测试中改变了两个变量的经典调试错误,而另一个解决了我的问题。]
我发现了问题。这是我声明DatagramSocket似乎导致问题的方式。如果我使用DatagramChannel以下列方式打开DatagramSocket,则bind()调用成功。
DatagramChannel channel = DatagramChannel.open();
DatagramSocket socket = channel.socket();
答案 1 :(得分:2)
我偶然发现了这个问题并且找到了原因:如果你调用无参数构造函数new DatagramSocket()
,这会创建一个UDP数据报套接字,它绑定到任何可用的端口在本地主机上使用通配符地址&#34; (根据API文档)。所以这实际上意味着,Socket已经绑定了。我的#34;修复&#34;对此如下:
SocketAddress socketAddress = new SocketAddress(yourInetAddress, yourPort);
DatagramSocket serverSocket = new DatagramSocket(null);
serverSocket.bind(socketAddress);
这显式地创建了一个未绑定的Socket(通过DatagramSocket (SocketAddress localAddr)
构造函数),从而可以依次绑定Socket。
这可能是比创建不必要的频道更优雅的解决方案。
P.S。:奇怪的是,这是DatagramSocket
与TCP ServerSocket
的不同之处:后者的无参数构造函数将创建一个未绑定的ServerSocket,而不会触发此问题。