如何同时监控多个组播组
How to monitor multiple multicast groups at the same time
我目前正在使用 Ruby 1.8.7 开发 Linux 版本的 Windows 工具,该工具可根据用户配置的多播组检查最多 2 个接口上的多播数据和港口。
我之前有一个问题,我不确定如何收听多个多播频道,但这个问题已经从之前的问题中解决了。
这导致了下一个问题。我需要收听多个多播组并且:
确定每个特定组是否收到任何数据并报告哪些有数据哪些没有
同时在所有通道上侦听用户可配置超时期限内的数据
我正在尝试在单独的代码段中使它工作,其中多播组、端口和接口都是硬编码的,一旦我整理好并理解了它,我会将它迁移到用户输入的主程序中并且验证已经完成。我更新了我的简单程序代码,现在它看起来像:
#!/usr/bin/ruby
require 'socket'
require 'ipaddr'
require 'timeout'
MCAST_GROUP_A
{
:addr1 => '233.54.12.111',
:addr2 => '233.86.230.111',
:port => 26477,
:bindaddr => '172.31.230.156'
}
MCAST_GROUP_B =
{
:addr => '233.54.12.111',
:port => 18170,
:bindaddr => '172.31.230.156'
}
ipA1 = IPAddr.new(MCAST_GROUP_A[:addr1]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipA2 = IPAddr.new(MCAST_GROUP_A[:addr2]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipB = IPAddr.new(MCAST_GROUP_B[:addr]).hton + IPAddr.new(MCAST_GROUP_B[:bindaddr]).hton
begin
sockA = UDPSocket.open
sockB = UDPSocket.open
sockA.bind Socket::INADDR_ANY, MCAST_GROUP_A[:port]
sockB.bind Socket::INADDR_ANY, MCAST_GROUP_B[:port]
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA1
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA2
sockB.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipB
timeoutSeconds = 10
Timeout.timeout(timeoutSeconds) do
msg1, info1 = sockA.recvfrom(1024)
msg2, info2 = sockB.recvfrom(1024)
#puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
puts "MSG: <garbled> from #{info1[2]} (#{info1[3]})/#{info1[1]} len #{msg1.size}"
puts "MSG: <garbled> from #{info2[2]} (#{info2[3]})/#{info2[1]} len #{msg2.size}"
end
rescue Timeout::Error
puts "Nothing received connection timedout\n"
ensure
sockA.close
sockB.close
end
但这产生了问题,因为它报告没有收到任何东西,因为 B 套接字上的数据不存在。
我理解这是因为第二个 recvfrom 超时,因此我们最终进入了代码的救援部分。但由于这是我的第一个 Ruby 程序,我仍在学习它,所以我不确定如何解决它。
总之我需要了解的是:
由于 sockA 上有 2 个多播组,因此如何确定在哪个通道上接收到 sockA 数据
如何同时监控可配置数量的多播组数据,不会出现一次接收失败导致输出不正确的错误
要同时监视多个套接字,请使用select
函数。 This question 给出了如何在 Ruby 中完成的示例。
至少在 C 语言中,使用 IP_PKTINFO 套接字选项和 recvfrom
函数可以获取传入数据包的目标地址,但是它看起来不像 Ruby API 公开该功能。
我目前正在使用 Ruby 1.8.7 开发 Linux 版本的 Windows 工具,该工具可根据用户配置的多播组检查最多 2 个接口上的多播数据和港口。
我之前有一个问题,我不确定如何收听多个多播频道,但这个问题已经从之前的问题中解决了。
这导致了下一个问题。我需要收听多个多播组并且:
确定每个特定组是否收到任何数据并报告哪些有数据哪些没有
同时在所有通道上侦听用户可配置超时期限内的数据
我正在尝试在单独的代码段中使它工作,其中多播组、端口和接口都是硬编码的,一旦我整理好并理解了它,我会将它迁移到用户输入的主程序中并且验证已经完成。我更新了我的简单程序代码,现在它看起来像:
#!/usr/bin/ruby
require 'socket'
require 'ipaddr'
require 'timeout'
MCAST_GROUP_A
{
:addr1 => '233.54.12.111',
:addr2 => '233.86.230.111',
:port => 26477,
:bindaddr => '172.31.230.156'
}
MCAST_GROUP_B =
{
:addr => '233.54.12.111',
:port => 18170,
:bindaddr => '172.31.230.156'
}
ipA1 = IPAddr.new(MCAST_GROUP_A[:addr1]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipA2 = IPAddr.new(MCAST_GROUP_A[:addr2]).hton + IPAddr.new(MCAST_GROUP_A[:bindaddr]).hton
ipB = IPAddr.new(MCAST_GROUP_B[:addr]).hton + IPAddr.new(MCAST_GROUP_B[:bindaddr]).hton
begin
sockA = UDPSocket.open
sockB = UDPSocket.open
sockA.bind Socket::INADDR_ANY, MCAST_GROUP_A[:port]
sockB.bind Socket::INADDR_ANY, MCAST_GROUP_B[:port]
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA1
sockA.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipA2
sockB.setsockopt Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ipB
timeoutSeconds = 10
Timeout.timeout(timeoutSeconds) do
msg1, info1 = sockA.recvfrom(1024)
msg2, info2 = sockB.recvfrom(1024)
#puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}"
puts "MSG: <garbled> from #{info1[2]} (#{info1[3]})/#{info1[1]} len #{msg1.size}"
puts "MSG: <garbled> from #{info2[2]} (#{info2[3]})/#{info2[1]} len #{msg2.size}"
end
rescue Timeout::Error
puts "Nothing received connection timedout\n"
ensure
sockA.close
sockB.close
end
但这产生了问题,因为它报告没有收到任何东西,因为 B 套接字上的数据不存在。
我理解这是因为第二个 recvfrom 超时,因此我们最终进入了代码的救援部分。但由于这是我的第一个 Ruby 程序,我仍在学习它,所以我不确定如何解决它。
总之我需要了解的是:
由于 sockA 上有 2 个多播组,因此如何确定在哪个通道上接收到 sockA 数据
如何同时监控可配置数量的多播组数据,不会出现一次接收失败导致输出不正确的错误
要同时监视多个套接字,请使用select
函数。 This question 给出了如何在 Ruby 中完成的示例。
至少在 C 语言中,使用 IP_PKTINFO 套接字选项和 recvfrom
函数可以获取传入数据包的目标地址,但是它看起来不像 Ruby API 公开该功能。