gpt4 book ai didi

java - MulticastSocket 构造函数和绑定(bind)到端口或 SocketAddress

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:36:14 25 4
gpt4 key购买 nike

我可能对此处的绑定(bind)一词有根本的误解,但我对 MulticastSocket 的用法感到困惑。它是构造函数。他们不会做我理解他们应该做的事情,因此任何能帮助我消除误解的人都将不胜感激。

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

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)它停止工作。似乎我只能使用绑定(bind)到端口的构造函数让它工作,所以当这个构造函数被调用时它究竟绑定(bind)到什么,因为我在这个阶段没有指定网络适配器。 (我知道我稍后会加入具有特定 NetworkInterface 的组,但是我如何确定在构造函数调用期间它不会绑定(bind)到任何适配器?)

我也可以在不指定适配器的情况下加入一个组,然后我不知道它绑定(bind)到哪个适配器。

任何人都可以解释绑定(bind)到端口的真正作用是什么,是否可以只在特定的 NetworkInterface 上监听?

更新 #1 **

看了这么多回复,和同事讨论了一下,以下是我对Java MulticastSocket的理解:
  • MulticastSocket() 创建一个多播套接字绑定(bind)一个随机选择的端口(由主机的底层操作系统绑定(bind)到通配符地址 0.0.0.0 即所有网卡。但是,使用 null 调用此构造函数会创建一个未绑定(bind)的 MulticastSocket。在这种情况下调用`bind (SocketAddress) 方法绑定(bind)到 IP 和端口。
  • MulticastSocket(int port) 创建一个绑定(bind)到特定端口但在每个 IP 地址上的多播套接字。
  • MulticastSocket(SocketAddress sa) 创建一个绑定(bind)到指定 IP 地址(可以是任何 IP 地址,甚至是无效的多播地址)和端口的多播套接字。

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

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

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

    ** 更新 2 **
    引自“UNIX 网络编程”,Stevens、Fenner、Rudoff:

    To receive a multicast datagram, a process must join the multicast group and it must also bind a UDP socket to the prot number that will be used as destination port number for datagrams sent to the group. The two operations are distinct and both are required. Joining the group tells the host's IP layer and datalink layer to receive multicast datagrams sent to that group. Binding the port is how the application specifies to UDP that it wants to receive datagrams sent to that port. Some applications also bind the multicast address to the socket, in addition to the port. this prevents any other datagrams that might be received for that port to other unicast, broadcast or multicast addresses from being delivered to the socket.



    我想这就解释了这一切。

    ** 更新 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"));*/

    最佳答案

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

    可以绑定(bind)到特定的 IP 地址,这隐式表示相应的 NIC,但是某些系统(例如 Linux)似乎希望多播套接字(如果绑定(bind))绑定(bind)到多播组本身。这对我来说没有任何意义:如果你想加入另一个小组怎么办?

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

    关于java - MulticastSocket 构造函数和绑定(bind)到端口或 SocketAddress,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19392173/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com