Java DatagramChannel SocketException“;无效参数";

Java DatagramChannel SocketException“;无效参数";,java,nonblocking,channel,datagram,socketexception,Java,Nonblocking,Channel,Datagram,Socketexception,我的代码在DatagramChannel中调用send()时抛出SocketException。javadoc甚至没有提到这是可能的。我在某处找到一篇帖子,建议使用IPv4协议栈,使用“-Djava.net.preferIPv4Stack=true”,这没有帮助。我只想发送一个非阻塞DNS请求 Exception in thread "main" java.net.SocketException: Invalid argument at sun.nio.ch.DatagramChanne

我的代码在DatagramChannel中调用send()时抛出SocketException。javadoc甚至没有提到这是可能的。我在某处找到一篇帖子,建议使用IPv4协议栈,使用“-Djava.net.preferIPv4Stack=true”,这没有帮助。我只想发送一个非阻塞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));

    }
}

我认为您的问题在于,通过调用
InetAddress.getLocalHost()
,显式地将客户端的本地套接字绑定到localhost。而不是做:

channel.bind(new InetSocketAddress(ip, port));
您应该实例化
InetSocketAddress
,而不指定IP部分。然后,系统将套接字绑定到所有可用接口(
0.0.0.0
):

如果您希望明确,也可以这样调用:

channel.bind(new InetSocketAddress("*", port));

这为我解决了问题。基本原理是客户端套接字必须绑定到传出接口,而不是环回。

无法复制:我在Linux上的Java 1.8.0上也不例外。@MvG您使用的是什么版本?很抱歉响应太晚,您在我度假时发送了答复,我错过了。你的解决方案奏效了,我没有看到,这让人恼火:)
channel.bind(new InetSocketAddress(port));
channel.bind(new InetSocketAddress("*", port));