如何广播HTTP请求?

时间:2018-01-29 21:31:33

标签: c# http mono broadcast

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

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

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

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

1 个答案:

答案 0 :(得分:3)

如评论中所述,HTTP无法像这样广播。

枚举IP范围内的所有IP地址,并向每个IP地址发送一个HTTP请求,看看是否存在不太好的想法。一个非常好的想法有多少取决于你的DHCP服务器给出的Private IP Address Range和子网掩码中的哪一个

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

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

如果你的IP范围不是192.168.0.0/24,那么你也无法同时探测所有这些。即使您不介意产生6.5万个线程,您的机器也没有足够的TCP端口可用于响应(取决于操作系统,您可能会得到30和39),因此您和#39;我必须分批完成它们。

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

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

UDP可能更好

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

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

您的网络配置中的不同路由器通常可以设置为转发您的UDP广播请求和相关响应,以便以最少的配置(不超过您需要做的任何事情来使HTTP请求工作)您可以在网段外搜索。

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

查找子网

无论您选择哪种方式,都可以使用以下代码完成所有子网的广播地址或完整的IP地址集。它将在您机器上的所有适配器(在全世界所有的杜松子酒关节中)的所有子网上找到所有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;
    }
}

希望这有帮助

相关问题