如何广播HTTP请求?
How to broadcast HTTP request?
我正在 Mono/C# 中设计一个带有传感器节点的数据采集系统,该系统使用 HTTP 与服务器通信。我正在使用基本的 HttpWebRequest 和 HttpListener 来实现通信。
服务器将有一个带有搜索按钮的应用程序,用于查找和显示 LAN 中存在的节点。基本上,节点将侦听在特定端口上接收到的特定 Hello 消息(HTTP 请求),并在收到消息时以其 ID 进行响应。
我的问题是:如何将 HTTP 请求广播到网络中的所有节点?或者,如何获取局域网中连接的所有机器的 IP 地址,以便向每台机器发送请求?
如果这是一种更简单的实现方法,我愿意接受新的建议。谢谢!
如评论所述,HTTP不能这样广播
枚举您的 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 请求发送到,
- 如果您的 LAN 使用 172...* 地址,您将获得 1'048'575 个 IP 地址,并且
- 如果您的 LAN 使用 10...* 地址范围,您将有令人印象深刻的 16'777'215 个地址可供搜索。
您可能需要搜索很多 IP 地址。
如果您的 IP 范围不是 192.168.0.0/24,那么您也无法同时探测所有这些。即使你不介意生成 65,000 个线程,你的机器也没有足够的 TCP 端口用于响应(取决于 OS,你可能会得到 30'000)所以你会必须分批处理。
此外,如果你的网络再复杂一点,用vLAN或路由器来分隔网络的不同区域,你的机器将无法自行枚举这些区域所使用的范围。到那时,您可能会找到一种方法来查询路由器或 ActiveDirectory 以查找网段之外的 IP 范围或主机。
总而言之,这不是一个好主意。
UDP 可能更好
更好的方法是使用(正如其他人所建议的那样)UDP 广播。您的每个传感器节点都将侦听特定的 UDP 端口,您的服务器将向您的子网的广播 IP 地址发送一条 UDP 消息。每个节点都会收到消息,然后节点上的代码会将某种形式的响应发送回 UDP 广播的源(服务器)。然后服务器将接收来自每个节点的 UDP 响应,其中包括每个节点的 IP 地址。
在代码级别,您创建一个套接字,使用选定的端口号为 UDP 配置它,然后您的服务器开始使用您选择的范例在该端口上接收数据(同步,begin/end,async/await).当数据到达端口时,您的回调函数被触发,并传递接收到的数据和发送它的服务的 IPEndPoint。
您的网络配置中的不同路由器通常可以设置为转发您的 UDP 广播请求和相关的响应,这样只需最少的配置(无论如何您都不需要做更多的事情来让 HTTP 请求正常工作)你可以在你的网段之外搜索。
可在 C# 中找到简单 UDP 服务器的示例 here。
寻找子网
无论您选择哪种方式,都可以使用以下代码获取所有子网及其广播地址或完整的 IP 地址集。它将找到您机器上所有适配器(在全世界所有 gin-joints 中)的所有子网上的所有 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;
}
}
希望对您有所帮助
我正在 Mono/C# 中设计一个带有传感器节点的数据采集系统,该系统使用 HTTP 与服务器通信。我正在使用基本的 HttpWebRequest 和 HttpListener 来实现通信。
服务器将有一个带有搜索按钮的应用程序,用于查找和显示 LAN 中存在的节点。基本上,节点将侦听在特定端口上接收到的特定 Hello 消息(HTTP 请求),并在收到消息时以其 ID 进行响应。
我的问题是:如何将 HTTP 请求广播到网络中的所有节点?或者,如何获取局域网中连接的所有机器的 IP 地址,以便向每台机器发送请求?
如果这是一种更简单的实现方法,我愿意接受新的建议。谢谢!
如评论所述,HTTP不能这样广播
枚举您的 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 请求发送到,
- 如果您的 LAN 使用 172...* 地址,您将获得 1'048'575 个 IP 地址,并且
- 如果您的 LAN 使用 10...* 地址范围,您将有令人印象深刻的 16'777'215 个地址可供搜索。
您可能需要搜索很多 IP 地址。
如果您的 IP 范围不是 192.168.0.0/24,那么您也无法同时探测所有这些。即使你不介意生成 65,000 个线程,你的机器也没有足够的 TCP 端口用于响应(取决于 OS,你可能会得到 30'000)所以你会必须分批处理。
此外,如果你的网络再复杂一点,用vLAN或路由器来分隔网络的不同区域,你的机器将无法自行枚举这些区域所使用的范围。到那时,您可能会找到一种方法来查询路由器或 ActiveDirectory 以查找网段之外的 IP 范围或主机。
总而言之,这不是一个好主意。
UDP 可能更好
更好的方法是使用(正如其他人所建议的那样)UDP 广播。您的每个传感器节点都将侦听特定的 UDP 端口,您的服务器将向您的子网的广播 IP 地址发送一条 UDP 消息。每个节点都会收到消息,然后节点上的代码会将某种形式的响应发送回 UDP 广播的源(服务器)。然后服务器将接收来自每个节点的 UDP 响应,其中包括每个节点的 IP 地址。
在代码级别,您创建一个套接字,使用选定的端口号为 UDP 配置它,然后您的服务器开始使用您选择的范例在该端口上接收数据(同步,begin/end,async/await).当数据到达端口时,您的回调函数被触发,并传递接收到的数据和发送它的服务的 IPEndPoint。
您的网络配置中的不同路由器通常可以设置为转发您的 UDP 广播请求和相关的响应,这样只需最少的配置(无论如何您都不需要做更多的事情来让 HTTP 请求正常工作)你可以在你的网段之外搜索。
可在 C# 中找到简单 UDP 服务器的示例 here。
寻找子网
无论您选择哪种方式,都可以使用以下代码获取所有子网及其广播地址或完整的 IP 地址集。它将找到您机器上所有适配器(在全世界所有 gin-joints 中)的所有子网上的所有 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;
}
}
希望对您有所帮助