代码之家  ›  专栏  ›  技术社区  ›  Cristian M

如何广播HTTP请求?

  •  2
  • Cristian M  · 技术社区  · 6 年前

    我正在设计一个带有传感器节点的数据采集系统,这些传感器节点使用Mono/C中的HTTP与服务器进行通信。我使用基本的HttpWebRequest和HttpListener来实现通信。

    服务器将有一个带有搜索按钮的应用程序,用于查找和显示局域网中存在的节点。基本上,节点将侦听在特定端口上接收的特定Hello消息(HTTP请求),并在接收到该消息时使用其ID进行响应。

    我的问题是: 如何将HTTP请求广播到网络中的所有节点?或者,如何获取LAN中连接的所有机器的IP地址,以便将请求发送给每个机器?

    如果这是一种更简单的实现方法,我愿意接受新的建议。谢谢你!

    1 回复  |  直到 6 年前
        1
  •  4
  •   Trevor    6 年前

    如评论中所述,HTTP不能像这样广播。

    列举IP范围内的所有IP地址,并向每个IP地址发送HTTP请求,以查看是否有不太好的想法。一个不太好的主意有多大程度上取决于 Private IP Address Range DHCP服务器提供的子网掩码

    • 最常见的配置使用192.168..*范围为255.255.255.0掩码(也称为192.168.0.0/24),仅提供255个地址。
    • 如果您的LAN使用192.168..*范围(掩码为255.255.0.0),此代码将为您提供65'535个IP地址,供您将HTTP请求发送到,
    • 如果您的LAN使用172…*地址,您将获得1'048'575个IP地址,并且
    • 如果您的LAN使用10…*地址范围,您将有令人印象深刻的16'777'215个地址可供搜索。

    你可能需要搜索很多IP地址。

    如果您的IP范围不是192.168.0.0/24,那么您也无法同时探测所有这些。即使您不介意生成65000个线程,您的机器也没有足够的TCP端口可用于响应(根据操作系统的不同,您可能会得到30000个),因此您必须成批处理它们。

    此外,如果您的网络甚至有点复杂,使用VLAN或路由器来分隔网络的不同区域,那么您的计算机将无法自行枚举这些区域使用的范围。此时,您可能会找到一种查询路由器或ActiveDirectory的方法,以查找网段以外的IP范围或主机。

    总而言之,这不是一个好主意。

    UDP可能更好

    更好的方法是使用UDP广播(正如其他人所建议的那样)。每个传感器节点将侦听特定的UDP端口,服务器将向子网的广播IP地址发送一条UDP消息。每个节点都将接收消息,然后节点上的代码将向UDP广播源(服务器)发送某种形式的响应。然后,服务器将从每个节点接收UDP响应,其中包括每个节点的IP地址。

    在代码级别,您创建一个套接字,使用选定的端口号将其配置为UDP,然后服务器开始使用您选择的范例(同步、开始/结束、异步/等待)在该端口上接收数据。当数据到达端口时,将启动回调函数,并将接收到的数据和发送该数据的服务的IPEndPoint传递给您。

    通常可以将网络配置中的不同路由器设置为转发UDP广播请求和相关响应,以便在最小配置的情况下(不超过让HTTP请求正常工作所需的配置),您可以在网段之外进行搜索。

    可以找到C#中简单UDP服务器的示例 here .

    查找子网

    无论您选择哪种方式,都可以使用以下代码获取所有子网及其广播地址或完整的IP地址集。它将找到您机器上所有适配器(世界上所有gin接头)上所有子网上的所有IP地址。

    此代码不会消除127。 . .* 本地地址,您可能希望这样做,以避免再进行1600万个地址的无意义搜索。

    foreach ( var lSubnet in GetLocalSubnets() )
    {
        var lBroadcast = lSubnet.subnetBroadastAddress;
        var lAddresses = new List<IPAddress>( lSubnet.GetAllAddresses() );
    }
    
    public static IEnumerable<IpAddressSubnet> GetLocalSubnets()
    {
        foreach (NetworkInterface lAdapter in NetworkInterface.GetAllNetworkInterfaces())
        {
            foreach (UnicastIPAddressInformation lAdapterIpAddress in lAdapter.GetIPProperties().UnicastAddresses)
            {
                if (lAdapterIpAddress.Address.AddressFamily == AddressFamily.InterNetwork)
                {
                    yield return new IpAddressSubnet(lAdapterIpAddress.Address, lAdapterIpAddress.IPv4Mask);
                }
            }
        }
        yield break;
    }
    
    public class IpAddressSubnet
    {
        public IpAddressSubnet(IPAddress pAddress, IPAddress pSubnetMask)
        {
            address = pAddress;
            subnetMask = pSubnetMask;
    
            var lAddressBytes = pAddress.GetAddressBytes();
            var lSubmaskBytes = pSubnetMask.GetAddressBytes();
            var lSubmaskInverted = lSubmaskBytes.Select((b) => (byte)(b ^ 255)).ToArray();
    
            var lSubnetBaseAddressBytes = lAddressBytes.Zip(lSubmaskBytes, (a, m) => (byte)(a & m)).ToArray();
            subnetBaseAddress = new IPAddress(lSubnetBaseAddressBytes);
            subnetBaseAddressUint = BitConverter.ToUInt32( lSubnetBaseAddressBytes.Reverse().ToArray(), 0 );
    
            subnetBroadastAddress = new IPAddress(lAddressBytes.Zip(lSubmaskInverted, (a, m) => (byte)(a | m)).ToArray());
            subnetSize = BitConverter.ToUInt32( lSubmaskInverted.Reverse().ToArray(), 0 );
        }
    
        public IPAddress address { get; set; }
        public IPAddress subnetMask { get; set; }
        public IPAddress subnetBaseAddress { get; set; }
        uint subnetBaseAddressUint { get; set; }
        public IPAddress subnetBroadastAddress { get; set; }
        public uint subnetSize { get; set; }
    
        public IEnumerable<IPAddress> GetAllAddresses()
        {
            for ( uint i = 0 ; i < subnetSize - 1 ; ++ i )  // Remove 1 for the broadcast address
            {
                uint lIp = subnetBaseAddressUint + i;
                yield return new IPAddress( BitConverter.GetBytes(lIp).Reverse().ToArray() );
            }
            yield break;
        }
    }
    

    希望这有帮助