在这里,我可能对绑定一词有一个根本的误解,但我对MulticastSocket及其构造函数的用法感到困惑。他们不做我理解他们应该做的事,任何能帮助我澄清我误解的人都应该这样做。
首先,我所要达到的目标。我尝试编写一个简短的程序,在MulticastSocket特定的网络适配器上创建一个绑定(即侦听),然后加入特定的多播组。我已经尝试了以下(客户端)代码的工作正常,我可以多播一个数据包到它,而不需要多播套接字超时。
public class Main {
public static final int DEFAULT_MULTICAST_PORT = 5555;
public static final String multicastGroup = "225.4.5.6";
public static final String adapterName = "eth0";
public static final int MAX_PACKET_SIZE = 65507;
CharBuffer charBuffer = null;
Charset charset = Charset.defaultCharset();
CharsetDecoder decoder = charset.newDecoder();
static ByteBuffer message = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
static boolean loop = true;
static byte[] buffer = new byte[MAX_PACKET_SIZE];
public static void main(String[] args) {
try {
//MulticastSocket mSocket = new MulticastSocket(new InetSocketAddress("192.168.2.23", DEFAULT_MULTICAST_PORT));
MulticastSocket mSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
mSocket.setReuseAddress(true);
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByName(adapterName);
mSocket.joinGroup(new InetSocketAddress(multicastGroup, DEFAULT_MULTICAST_PORT),NetworkInterface.getByName(adapterName));
DatagramPacket p = new DatagramPacket(buffer, MAX_PACKET_SIZE);
while (loop){
try{
mSocket.receive(p);
System.out.println("Packet Received.");
} catch (SocketTimeoutException ex){
System.out.println("Socket Timed out");
}
}
} catch (IOException ex){
System.err.println(ex);
}
}}
不幸的是,一旦我将MulticastSocket构造函数更改为MulticastSocket(SocketAddress bindaddr),它就停止工作。看来我只能使用绑定到端口的构造函数才能工作,所以当调用这个构造函数时,它到底绑定到什么地方,因为在这个阶段我还没有指定一个网络适配器。(我知道稍后我会使用特定的NetworkInterface加入这个组,但是如何确保在构造函数调用期间它不会绑定到任何适配器?)
我也可以在不指定适配器的情况下加入一个组,然后我不知道它绑定到哪个适配器。
有人能解释到端口的绑定实际上只起什么作用吗?是否可以只在特定的NetworkInterface上侦听?
更新#1 **
在阅读了到目前为止的答复并与一位同事讨论了这一点之后,以下是我对Java MulticastSocket的理解:
使用选项2,这可能意味着发送到指定端口的任何数据包,无论其实际目的地是什么,都将传递给MulticastSocket。我可能会说,因为多播数据包只有在组已加入时才会到达(但如果端口号匹配,其他发送到非多播地址的数据包就会到达?)
使用选项3,我可以绑定到IP地址,并且只有目的地匹配的数据包才能到达套接字。使用此选项绑定到特定网络接口的IP是完全可行的,但是不会接收多播数据包,因为它们不会被发送到网卡的特定IP地址(这就是为什么我从未在代码示例中看到它们到达)。也可以绑定到有效的多播地址,但在这种情况下,不管对joinGroup()的调用如何,只有目的地与绑定多播地址匹配的特定数据包才会到达套接字。
现在,对joinGroup()的调用对套接字本身没有任何作用,而是向底层网络系统发出IGMP请求,以确保路由器、OS本身等实际上开始将指定的多播数据包路由到硬件上,并通过网络堆栈最终路由到MulticastSocket本身。
** Update 2 *引用"UNIX网络编程“,Stevens,,Rudoff:
要接收多播数据报,进程必须加入多播组,并且它还必须将UDP套接字绑定到prot编号,prot编号将用作发送到组的数据报的目标端口号。这两个操作是不同的,两者都是必需的。加入这个组会告诉主机的IP层和数据链路层接收发送给该组的多播数据报。绑定端口是应用程序如何向UDP指定它希望接收发送到该端口的数据报。除了端口之外,一些应用程序还将多播地址绑定到套接字。这将防止为该端口接收到其他单播、广播或多播地址的任何其他数据报被传递到套接字。
我想这就解释了一切。
** 更新3 *只是想发布我测试过的代码,注释解释了每个代码发生了什么。
/**
* This first creates an UNBOUND Multicast Socket and then binds to
* a port (but accepting the wildcard IP 0.0.0.0.
* The Following WORKS:
*/
/*MulticastSocket mSocket = new MulticastSocket(null);
mSocket.bind(new InetSocketAddress(DEFAULT_MULTICAST_PORT));
mSocket.setReuseAddress(true);
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByName(adapterName);
mSocket.joinGroup(InetAddress.getByName(multicastGroup));
*/
/**
* The following creates a a network socket and binds in the constructor
* to a local adapter and port. Consequently it DOES not work because
* it only allows destination ips that match the bound address & port
* even though the desired group is joined.
*/
/*MulticastSocket mSocket = new MulticastSocket(new InetSocketAddress("192.168.2.23", DEFAULT_MULTICAST_PORT));
mSocket.setReuseAddress(true);
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByName(adapterName);
mSocket.joinGroup(InetAddress.getByName(multicastGroup));*/
/**
* The following binds to the same multicast group this is 'joined' later
* and this works correctly. However if the join() is NOT called, no packets
* arrive at the socket, as expected.
*/
/*MulticastSocket mSocket = new MulticastSocket(new InetSocketAddress(multicastGroup, DEFAULT_MULTICAST_PORT));
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByName(adapterName);
// Comment out the following line and it no longer workds correctly.
mSocket.joinGroup(InetAddress.getByName(multicastGroup));*/
/**
* The following binds to a a specified port on 0.0.0.0 and joins
* a specific Multicast group on a specific adapter. This must mean that the IGMP must occur
* on the specified adapter.
*
* ** This will ALSO receive packets addressed DIRECTLY to the ip 192.168.2.23 with the same
* port as DEFAULT_MULTICAST_POR ***ONLY!!***
*/
MulticastSocket mSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
mSocket.setReuseAddress(true);
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByInetAddress(InetAddress.getByName("192.168.2.23"));
mSocket.joinGroup(new InetSocketAddress(multicastGroup, DEFAULT_MULTICAST_PORT),NetworkInterface.getByName(adapterName));
/**
* The following binds to a specific address and port (i.e. adapter address)
* and then ONLY accepts UDP packets with destination equal to that IP.
*/
/*MulticastSocket mSocket = new MulticastSocket(new InetSocketAddress("192.168.2.23", DEFAULT_MULTICAST_PORT));
mSocket.setReuseAddress(true);
mSocket.setSoTimeout(5000);
NetworkInterface nic = NetworkInterface.getByInetAddress(InetAddress.getByName("192.168.2.23"));*/发布于 2013-10-15 22:42:49
如果在创建或绑定本地IP地址时没有指定它,则它绑定到0.0.0.0,这意味着“通过任何NIC接受输入”。这通常是你想要的。
可以绑定到特定的IP地址,这意味着相应的NIC,但一些系统(如Linux )似乎期望多播套接字(如果绑定)绑定到多播组本身。这对我来说没有任何意义:如果你想加入另一个团体,该怎么办?
我认为最好的,也是最便携的想法是听0.0.0.0,通过一个特定的NIC,或者通过所有的NIC,一次一个。后者在多宿主中是必要的,除非您确信到多播组的默认路由是您希望发送连接请求的路由,因为如果不指定连接接口,则会发生这种情况。
发布于 2013-10-15 22:55:53
我认为您忽略了地址绑定的要点:
http://download.java.net/jdk7/archive/b123/docs/api/java/net/MulticastSocket.html
多播组由D类IP地址和标准UDP端口号指定。D类IP地址范围为224.0.0.0至239.255.255.255 (含)。地址224.0.0.0是保留的,不应该使用。
https://stackoverflow.com/questions/19392173
复制相似问题