DatagramChannel SocketException "Invalid argument"
DatagramChannel SocketException "Invalid argument"
我的代码在 DatagramChannel 中调用 send() 时抛出 SocketException。 javadoc 甚至没有提到这是可能的。我在某处发现 post 建议使用“-Djava.net.preferIPv4Stack=true”来使用 IPv4 堆栈,但这没有帮助。我只想发送一个非阻塞 DNS 请求。
Exception in thread "main" java.net.SocketException: Invalid argument
at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
at Test.main(Test.java:31)
这是相关代码:
public class Test {
private static final byte[] request = hexStringToByteArray("674B010000010000000000000377777706676F6F676C6503636F6D0000010001");
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(final String[] args) throws IOException {
String ip = InetAddress.getLocalHost().getHostAddress();
int port = 1024 + (new Random()).nextInt(64507);
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(ip, port));
int sent = channel.send(ByteBuffer.wrap(request), new InetSocketAddress(InetAddress.getByName("8.8.8.8"), 53));
}
}
编辑:因为这里无法重现一些版本:
jurgen@home:~/workspace/Resolver/bin$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
jurgen@home:~/workspace/Resolver/bin$ uname -a
Linux home 3.13.0-44-generic #73-Ubuntu SMP Tue Dec 16 00:22:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
jurgen@home:~/workspace/Resolver/bin$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.1 LTS
Release: 14.04
Codename: trusty
jurgen@home:~/workspace/Resolver/bin$ java Test
Exception in thread "main" java.net.SocketException: Invalid argument
at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
at Test.main(Test.java:31)
我认为您的问题是您通过调用 InetAddress.getLocalHost()
将客户端的本地套接字显式绑定到 localhost。而不是做:
channel.bind(new InetSocketAddress(ip, port));
您应该在不指定 IP 部分 的情况下实例化 InetSocketAddress
。然后系统会将套接字绑定到所有可用接口(0.0.0.0
):
channel.bind(new InetSocketAddress(port));
如果想显式也可以这样调用:
channel.bind(new InetSocketAddress("*", port));
这解决了我的问题。基本原理是客户端套接字必须绑定到 传出接口 而不是环回。
我的代码在 DatagramChannel 中调用 send() 时抛出 SocketException。 javadoc 甚至没有提到这是可能的。我在某处发现 post 建议使用“-Djava.net.preferIPv4Stack=true”来使用 IPv4 堆栈,但这没有帮助。我只想发送一个非阻塞 DNS 请求。
Exception in thread "main" java.net.SocketException: Invalid argument
at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
at Test.main(Test.java:31)
这是相关代码:
public class Test {
private static final byte[] request = hexStringToByteArray("674B010000010000000000000377777706676F6F676C6503636F6D0000010001");
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static void main(final String[] args) throws IOException {
String ip = InetAddress.getLocalHost().getHostAddress();
int port = 1024 + (new Random()).nextInt(64507);
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new InetSocketAddress(ip, port));
int sent = channel.send(ByteBuffer.wrap(request), new InetSocketAddress(InetAddress.getByName("8.8.8.8"), 53));
}
}
编辑:因为这里无法重现一些版本:
jurgen@home:~/workspace/Resolver/bin$ java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
jurgen@home:~/workspace/Resolver/bin$ uname -a
Linux home 3.13.0-44-generic #73-Ubuntu SMP Tue Dec 16 00:22:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
jurgen@home:~/workspace/Resolver/bin$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.1 LTS
Release: 14.04
Codename: trusty
jurgen@home:~/workspace/Resolver/bin$ java Test
Exception in thread "main" java.net.SocketException: Invalid argument
at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(DatagramChannelImpl.java:536)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:513)
at sun.nio.ch.DatagramChannelImpl.send(DatagramChannelImpl.java:477)
at Test.main(Test.java:31)
我认为您的问题是您通过调用 InetAddress.getLocalHost()
将客户端的本地套接字显式绑定到 localhost。而不是做:
channel.bind(new InetSocketAddress(ip, port));
您应该在不指定 IP 部分 的情况下实例化 InetSocketAddress
。然后系统会将套接字绑定到所有可用接口(0.0.0.0
):
channel.bind(new InetSocketAddress(port));
如果想显式也可以这样调用:
channel.bind(new InetSocketAddress("*", port));
这解决了我的问题。基本原理是客户端套接字必须绑定到 传出接口 而不是环回。