Multicasting in Ruby

最近有一个项目准备用多播来做心跳. 网上转了一篇ruby多播的文章.

原文

http://onestepback.org/index.cgi/Tech/Ruby/MulticastingInRuby.red

Multicasting in Ruby

It’s a bit hard to dig up, but I did figure out how to do UDP packet multicasting in Ruby.

Multicasting

I’ve been playing around with some network peer to peer discovery techniques and wanted to try some of them out in Ruby. The trick to self discovery is the ability to send network packets without knowing the address of the receiver. To do this, you either have to broadcast or multicast.

Because broadcasted packets are received by every device on the local network, it is generally considered good manners to not use broadcasted packets.

Multicasting, on the other hand, is only received by hosts that explicitly express an interest in the multicast address. Although abuse of multicasting is still bad manners, it is a better option than broadcasting.

Sending Multicast Packets

The IP addresses 224.0.0.0 through 239.255.255.255 are reserved for multicast messages. Simply sending a UDP messsage to an address in that range is sufficient.

One minor refinement is to set the TTL (Time To Live) option on the socket. My understanding is that this controls how far the packet is propagated. As polite net-citizens, we don’t want our multicast packets travelling too far abroad, so we set the TTL value to 1 (we need the ugly packing stuff because the value is passed directly to the C level setsockopt() function with no interpretation by Ruby).

So the Ruby code to send a multicast message is:

require 'socket'

MULTICAST_ADDR = "225.4.5.6" 

PORT= 5000

begin

  socket = UDPSocket.open

  socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_TTL, [1].pack('i'))

  socket.send(ARGV.join(' '), 0, MULTICAST_ADDR, PORT)

ensure

  socket.close 

end

Receiving Multicast Messages

Receiving a multicast message is a bit tricker. Since multicast messages are generally ignored unless someone has explicitly registered an interest in a particular address, there is a bit of setup that needs to be done.

Here’s the code for receiving multicast messages:

require 'socket'

require 'ipaddr'

MULTICAST_ADDR = "225.4.5.6" 

PORT = 5000

ip =  IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new("0.0.0.0").hton

sock = UDPSocket.new

sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip)

sock.bind(Socket::INADDR_ANY, PORT)

loop do

  msg, info = sock.recvfrom(1024)

  puts "MSG: #{msg} from #{info[2]} (#{info[3]})/#{info[1]} len #{msg.size}" 

end

The tricky part was figuring out the right setsockopt options and values needed to register interest in our multicast address. I had to do a little reading in the Unix man pages on the C level setsockopt() function call. The third option to the C function is a structure that contains two 4-byte IP addresses. The first IP address is the multicast address, and the second IP address is the address of the local host adapter that we wish to use to listen for the multicast. The 0.0.0.0 address means use any of the local network adapters. IPAddr handles parsing the human readable form of the IP address and returns a string of 4 bytes in the order needed by the C level setsockopt() function.

Usage

Save the above code in files named send.rb and rcv.rb. In one console window, type:

ruby rcv.rb

In another console window on the same or different machine (on the same local network), type:

ruby send.rb This is a test.

For more fun, bring up several receive windows and all will receive the messages send by the send script.

I can think of all kinds of fun things to do with this.

Update

I added the Time To Live option on send.

To set TTL for multicast packets you need to use IP_MULTICAST_TTL not IP_TTL. Also, setting IP_MULTICAST_LOOP to 0 will prevent the sender from seeing it's own packets.

时间: 2025-01-30 03:12:35

Multicasting in Ruby的相关文章

使用ruby与MS Access数据库交互

ruby常规访问access数据库的方法应该是使用DBI库 :   require 'dbi' DBI.connect("DBI:ADO:Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb;")   可是 简单尝试之后没能成功,提示找不到驱动器ADO,懒得再试,遂找其他方法. 一番搜索之后,发现可以用WIN32OLE来访问access,写一个简单的类包装之:   require 'win32ole' class AccessDb at

不使用 Ruby 的十个理由

这是一篇主观意识的文章.它的目的并不是要说服你使用或者不使用Ruby,或者其他任何技术.这篇文章所涉及到的环境是 Web 开发,而不是通用的编程.我想要通过这篇文章解释这些年来非 Ruby 社区对于 Ruby 的一些看法,并且提醒人们以开放的心态来面对新的事物.敬请欣赏! 我最近做了一个15分钟的演讲"我喜爱的 Ruby 语言以及它的生态系统".很显然我的言论让忠实的 PHP,.NET 和 Java 开发者感到不安.他们对 Ruby 不是好奇,而是感觉我在批评他们热爱的技术. 既然这不

ruby读取源代码自身的一种方法

    我们知道ruby中如果源代码中一行开头(必须在行的开头)有__END__标示,则表示下面的都是数据行,可以用IO对象DATA来访问这些行.但是如果我们用DATA.rewind一下的话,就可以将文件流指向文件开头鸟,然后就可以访问源代码本身啦: #!/usr/bin/ruby DATA.rewind i=1 DATA.each_line do |line| puts "#{'%03d' % i} #{line}" i+=1 end __END__ 运行结果: wisy@wisy-

linux下利用ruby做系统备份与还原

    啥都不说了,都在代码里 :) #!/usr/bin/ruby BAK_PATH = "/media/backup.tar.xz" def to_backup exclude_files = "" pre_cmd = "sudo tar -cvpJf #{BAK_PATH}" DATA.each_line do |line| exclude_files << "--exclude=#{line.chomp} "

ruby中如何调用与局部变量同名的私有方法

    如果ruby中一个局部变量名和私有方法名同名的话,默认该名称被解释为变量而不是方法: x=10; def x;puts "what?" end 当你输入x实际不能执行x方法.解释器只把x解释为变量.而且undef只能对方法而不能对变量下手,所以undef x仍然不行,变量还在那里!一种解决方法是将x方法转换为一个method,然后调用: x_f = method(:x) x_f[] 或者还有一种方法,就是方法别名!你可以指定x的一个别名,这时x肯定会解释为方法: alias n

ruby-求大神支招:如何学好Ruby语言

问题描述 求大神支招:如何学好Ruby语言 求大神支招:如何学好Ruby语言,还有Ruby什么版本用的人比较多,看什么书? 解决方案 请看这个:http://blog.csdn.net/liuk10/article/details/50976160

sass安装教程:ruby安装步骤和sass安装步骤

文章简介:因为sass依赖于ruby环境,所以装sass之前先确认装了ruby.先导官网下载个ruby. ruby安装 因为sass依赖于ruby环境,所以装sass之前先确认装了ruby.先导官网下载个ruby 在安装的时候,请勾选Add Ruby executables to your PATH这个选项,添加环境变量,不然以后使用编译软件的时候会提示找不到ruby环境 sass安装 如果你喜欢偷懒,或者你公司网络限制比较多,请直接看最后一段 安装完ruby之后,在开始菜单中,找到刚才我们安装

Java之父称PHP,Ruby以及C#,不足为惧

James Gosling上周参加了纽约的Sun 全球教育研讨会(World Wide Education & Research Conference),在会上这位Java 之父进行了演讲,并就提问进行了回答. 有些人问道当前Java 所面临的威胁时,Gosling给予了这样的回答,"PHP 和Ruby 是非常好的系统,但是它们作为脚本语言来发挥力量,只局限于网页这一领域内." 当Gosling谈到Microsoft 的C# 时,"曾经一度我们很担心他们会做出创造性的

使用Eclipse+RDT插件进行Ruby开发

简介 本文介绍如何在Eclipse中使用Ruby开发工具(RDT)插件进行Ruby开发.本文将有益于那些想学习如何使用Eclipse基础架构来进行Ruby开发的Ruby开发者,也有益于对Ruby开发感兴趣的Java开发者. 一. 为什么使用Ruby? 现在,为什么众多的Java开发者都关注Ruby?Ruby,是10年以前在日本创建的一种通用目的脚本语言,这是一种纯面向对象的语言.不同于Java技术,Ruby中的一切都是对象.Ruby的语法主要来源于Smalltalk,Python和Ada.象Ja