I am writing a small TimeP (RFC 868) server to sync time with some
networking equipment. The equipment that shall go nameless requires the
use of UDP.
As far as I can tell, my only option to write to a UDPSocket is to use
the send method, which takes a string. I need to send a 32bit integer
representing the date in a UDP packet and I’d love to use something
like:
myUDPsocket.send( Time.now.to_i, 0, host, port)
In my situation I can’t change the receiving program to accept a string
or I could do it that way. I can’t convert the integer to a string
either because that would blow my 32 bit requirement. Does anyone have
any idea?
~Parkingmeter
On 9/4/07, Ryan P. [email protected] wrote:
Try
ri Array#pack
[number].pack(‘i’)
should do the trick.
pth
Ryan P. wrote:
In my situation I can’t change the receiving program to accept a string
or I could do it that way. I can’t convert the integer to a string
either because that would blow my 32 bit requirement. Does anyone have
any idea?
Strings are just blobs of binary data, when they go through #send. The
receiver doesn’t know it started life as a ruby string.
If you want structure, use #pack. You’ll need to know what byte-order
the client and server should use to communicate. Assuming big-endian:
myUDPsocket.send([Time.now.to_i].pack(“N”), 0, host, port)
On Wed, 5 Sep 2007, Ryan P. wrote:
any idea?
A string is just a sequence of bytes. It can be anything.
In your case, you need to encode a decimal number as returned by
Time.now.to_i into 32 bits.
myUDPsocket.send( [Time.now.to_i].pack(‘i’) )
That may be what you need.
http://ruby-doc.org/core/classes/Array.html#M002245
For more information.
Kirk H.
On 9/4/07, [email protected] [email protected] wrote:
In my situation I can’t change the receiving program to accept a string
Actually, to support RFC-868, you have to use the same epoch that NTP
uses,
rather than the Unix epoch.
The current time in raw form would be Time.now.to_i + 0x83aa7e80. Pack
into
32 bits (taking care to keep the conversion unsigned), convert to
network-order as necessary, write a four-byte UDP datagram, and away you
go.
In article [email protected],
Ryan P. [email protected] writes:
In my situation I can’t change the receiving program to accept a string
or I could do it that way. I can’t convert the integer to a string
either because that would blow my 32 bit requirement. Does anyone have
any idea?
~Parkingmeter
Here, I had this script lying about from one of my earlier experiments
with Ruby sockets:
------ start of code -------
#! /usr/bin/env ruby
nettimesvr.rb - implement Time Server for RFC 868
PROGNAME = ‘nettimesvr.rb’
timeport = Socket.getservbyname(‘time’, ‘udp’) # port 37
timeport = 50037 # for testing
RFC868_POSIX_ADJMENT = 2_208_988_800 # diff between RFC 868 and POSIX
POSIX_EPOCH_ADJMENT = Time.gm(1970, ‘Jan’, 1).to_i
require ‘socket’
def curnettime()
return Time.new.to_i + (RFC868_POSIX_ADJMENT -
POSIX_EPOCH_ADJMENT)
end
port = timeport
begin
case ARGV.size
when 1: port = Integer(ARGV[0])
when 0: nil
else; abort “Usage: #{PROGNAME} [ port ]”
end
rescue ArgumentError => badarg
abort “Argument conversion error: #{badarg}”
end
puts “Listening on port #{port}\n”
UDPSocket.open { |sock|
sock.bind(Socket::INADDR_ANY, port)
loop do
# if we try to receive zero bytes, we get an
error
rmthost = sock.recvfrom(1) [1] # no body
expected
puts “Accepted request from #{rmthost [2]}”
nettime = [ curnettime() ].pack('N')
sock.send(nettime, 0, rmthost[2], rmthost[1])
end
}
------ end of code -------