【发布时间】:2015-11-26 10:33:15
【问题描述】:
我正在使用 Java 中的 DatagramSocket (UDP) 实现 DNS 服务器,代码如下所示:
try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", 53))) {
DatagramPacket request = ... // Init Packet
socket.receive(request);
... // Parse request, Resolve, then Generate reesponse
socket.send(response);
}
它在我的 PC 和大多数服务器(包括 aws、linode 等)上运行良好,但在具有双以太网适配器的服务器上运行不佳。
此服务器有一个网络配置:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 192.168.1.204
netmask 255.255.255.0
auto eth1
iface eth1 inet static
address 192.168.1.207
netmask 255.255.255.0
当我测试这个 DNS 时,我得到:
# nslookup
> server 192.168.1.207
Default server: 192.168.1.207
Address: 192.168.1.207#53
> info.dev.
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; reply from unexpected source: 192.168.1.204#53, expected 192.168.1.207#53
;; connection timed out; no servers could be reached
>
它似乎从 eth1 (192.168.1.207) 收到一个数据包,但发送到 eth0 (192.168.1.204)。而且我的代码不知道数据包是从哪个接口接收的。
try (DatagramSocket socket = new DatagramSocket(new InetSocketAddress("0.0.0.0", 53))) {
...
socket.receive(request); // local socket address not known :-(
...
socket.send(response); // local socket address not known :-(
}
Socket(TCP)可以做到这一点,但我不知道DatagramSocket(UDP)是否可以做到。
更新-1:
绑定一个接口而不是0.0.0.0,效果很好。
更新 2:
Socket (TCP) 可以获取本地地址和远程地址:
try (ServerSocket server = new ServerSocket(23)) {
try (Socket socket = server.accept()) {
System.out.println(socket.getLocalSocketAddress());
System.out.println(socket.getRemoteSocketAddress());
}
}
【问题讨论】:
-
0.0.0.0基本意思是“所有接口”,你不能把socket绑定到一个接口吗? -
我不明白这个问题。
DatagramSocket的本地地址是 0.0.0.0:53。您在构建它时指定的那个。它使用哪个接口进行回复由静态 IP 路由表确定。不是通过这个代码。不是编程问题:题外话。 -
@AndersR.Bystrup,绑定一个(例如 192.168.1.207)就可以了。
-
接受的 TCP 套接字的本地地址是客户端使用的目标地址。 UDP 没有接受的套接字,所以它没有那个。如果您打印出 ServerSocket 的本地地址,您将得到 0.0.0.0:23,这与您为 DatagramSocket 所做的非常相似,并且出于相同的原因。在 C 级别有一个 API 可以获取 数据报 的目标地址,但它没有在 Java 中实现。