Ok, I’ve narrowed it down partially to a newline issue with Marshal. Here
are a sample client and server to demonstrate. Just start the server in one
terminal and the client in another. Uncomment the appropriate lines to view
the different behavior. More comments at end…
SAMPLE SERVER
require ‘socket’
a = [“one”,“two”,“three”] # → This gets wonky results #a = [“one”,“two”,“three\n”] # → This works #a.push(“\n”) # → This causes “marshal data too short”
x = Marshal.dump(a)
Ok, I've narrowed it down partially to a newline issue with Marshal. Here
are a sample client and server to demonstrate. Just start the server in one
terminal and the client in another. Uncomment the appropriate lines to view
the different behavior. More comments at end...
use #read and #write rather than #puts#gets
[...]
while true
Thread.start(tcpServer.accept) do |s|
puts "Accepted connection: #{s}"
r = s.gets
puts "Got #{r} from client"
s.puts(x)
s.write([x.size].pack("N") + x)
s.close
end
end
[...]
v = s.gets
v = s.read(s.read(4).unpack("N")[0])
You can also verify that the string read has the good size
You can imagine the problem doing a gets on a socket containing that
last string, you aren’t getting your marshalled data back
You need to be reading all the data the client sends you, not line-wise.
Anyway, isn’t there DRuby - designed specifically for this kind of task?
Ok, I’ve narrowed it down partially to a newline issue with Marshal. Here
are a sample client and server to demonstrate. Just start the server in one
terminal and the client in another. Uncomment the appropriate lines to view
the different behavior. More comments at end…
SAMPLE SERVER
require ‘socket’
a = [“one”,“two”,“three”] # → This gets wonky results #a = [“one”,“two”,“three\n”] # → This works #a.push(“\n”) # → This causes “marshal data too short”
x = Marshal.dump(a)
Ok, I’ve narrowed it down partially to a newline issue with Marshal. Here
Curious. I didn’t expect marshal to make much use of whitespace…
are a sample client and server to demonstrate. Just start the server in one
[…]
The question I have, then, is how do I make sure that the marshalled object
is properly newline terminated?
When I wanted to do this I took the somewhat paranoid approach that
the only characters which are guaranteed to be passable between
systems are those that make up base64 – which is why base64 was
invented. See RFC989 Section 5.2 for details of this.
#!/usr/local/bin/ruby -w
Routine to encode an object into a string for transmission.
This takes an object, and it uses Marshal to create a string.
It then converts that string to base 64.
Marshal is used even on strings so that the process is reversible.
If this file is executed directly (i.e. not using “require”) then
it performs a basc self test.
class Encoded
include Marshal
def decode
@decoded
end
def encode
@encoded
end
private
def initialize(thing, code = true, depth=-1)
if code == true
@decoded = thing
@encoded = [Marshal.dump(@decoded,depth)].pack("m")
else
@encoded = thing
@decoded = Marshal.load(@encoded.unpack("m")[0])
end
end
end
if FILE == $0
print "Self test\n"
# define an arbitrary class to save.
class Fish
def swim
print "#{@name} is swimming\n"
end
def initialize(name)
@name = name
end
end
eric = Fish.new("Eric")
# Build an arrray of varying things to save...
x = [1,3.4,"hello!",{"this" => "that"},eric]
p(x)
e = Encoded.new(x, true, 20)
# s is the string to decode...
s = e.encode()
p(s.type())
p(s)
# decode it anew. New instance not a copy of the old
f = Encoded.new(s,false)
result = f.decode()
p(result)
p(result[-1].type())
# show that the las item is really of the class we defined.
result[-1].swim()