首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MulticastSocket构造函数和绑定到端口或SocketAddress

MulticastSocket构造函数和绑定到端口或SocketAddress
EN

Stack Overflow用户
提问于 2013-10-15 22:28:32
回答 2查看 7.4K关注 0票数 10

在这里,我可能对绑定一词有一个根本的误解,但我对MulticastSocket及其构造函数的用法感到困惑。他们不做我理解他们应该做的事,任何能帮助我澄清我误解的人都应该这样做。

首先,我所要达到的目标。我尝试编写一个简短的程序,在MulticastSocket特定的网络适配器上创建一个绑定(即侦听),然后加入特定的多播组。我已经尝试了以下(客户端)代码的工作正常,我可以多播一个数据包到它,而不需要多播套接字超时。

代码语言:javascript
复制
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的理解:

  1. MulticastSocket()创建一个多播套接字绑定随机选择的端口(由主机的底层操作系统绑定到通配符地址0.0.0.0,即所有网卡)。但是,使用null调用此构造函数将创建一个未绑定的MulticastSocket。在这个场景中,调用‘`bind(SocketAddress)方法绑定到IP和端口。
  2. MulticastSocket(int端口)在每个IP地址上创建绑定到特定端口的多播套接字。
  3. MulticastSocket(SocketAddress sa)创建一个绑定到指定IP地址(可以是任意IP地址,甚至是无效的多播地址)和端口的多播套接字。

使用选项2,这可能意味着发送到指定端口的任何数据包,无论其实际目的地是什么,都将传递给MulticastSocket。我可能会说,因为多播数据包只有在组已加入时才会到达(但如果端口号匹配,其他发送到非多播地址的数据包就会到达?)

使用选项3,我可以绑定到IP地址,并且只有目的地匹配的数据包才能到达套接字。使用此选项绑定到特定网络接口的IP是完全可行的,但是不会接收多播数据包,因为它们不会被发送到网卡的特定IP地址(这就是为什么我从未在代码示例中看到它们到达)。也可以绑定到有效的多播地址,但在这种情况下,不管对joinGroup()的调用如何,只有目的地与绑定多播地址匹配的特定数据包才会到达套接字。

现在,对joinGroup()的调用对套接字本身没有任何作用,而是向底层网络系统发出IGMP请求,以确保路由器、OS本身等实际上开始将指定的多播数据包路由到硬件上,并通过网络堆栈最终路由到MulticastSocket本身。

** Update 2 *引用"UNIX网络编程“,Stevens,,Rudoff:

要接收多播数据报,进程必须加入多播组,并且它还必须将UDP套接字绑定到prot编号,prot编号将用作发送到组的数据报的目标端口号。这两个操作是不同的,两者都是必需的。加入这个组会告诉主机的IP层和数据链路层接收发送给该组的多播数据报。绑定端口是应用程序如何向UDP指定它希望接收发送到该端口的数据报。除了端口之外,一些应用程序还将多播地址绑定到套接字。这将防止为该端口接收到其他单播、广播或多播地址的任何其他数据报被传递到套接字。

我想这就解释了一切。

** 更新3 *只是想发布我测试过的代码,注释解释了每个代码发生了什么。

代码语言:javascript
复制
/**
         * 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"));*/
EN

回答 2

Stack Overflow用户

发布于 2013-10-15 22:42:49

如果在创建或绑定本地IP地址时没有指定它,则它绑定到0.0.0.0,这意味着“通过任何NIC接受输入”。这通常是你想要的。

可以绑定到特定的IP地址,这意味着相应的NIC,但一些系统(如Linux )似乎期望多播套接字(如果绑定)绑定到多播组本身。这对我来说没有任何意义:如果你想加入另一个团体,该怎么办?

我认为最好的,也是最便携的想法是听0.0.0.0,通过一个特定的NIC,或者通过所有的NIC,一次一个。后者在多宿主中是必要的,除非您确信到多播组的默认路由是您希望发送连接请求的路由,因为如果不指定连接接口,则会发生这种情况。

票数 2
EN

Stack Overflow用户

发布于 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是保留的,不应该使用。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19392173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档