Sending Binary Data?

Hello Ruby Gurus!

My friend and I are writing a chat/IM client in Ruby. It's nothing special, but it's helping us learn the language, especially the lower level networking parts really well and I'm thoroughly enjoying the project so far. I thought implementing file transfers would be pretty nifty, but I'm running into some problems. I did a simple copy by reading the file (a picture) and adding the lines to a string, and writing that string out to a new file:

a = String.new

IO.foreach("lighter.jpg") do |line|
  a += line
end

file = File.open("new.jpg","w")
file.write(a)
file.close

And it worked swimmingly, however, when I tried to do this over a TCPClient/Server:

server.rb

require 'socket'
port = 9191
file = File.open("omgnew.jpg","w+")
server = TCPServer.new('localhost', port)
while session = server.accept
  file.write(session.gets)
  server.close
  file.close
end

client.rb

require 'socket'

server = TCPSocket.new('localhost',9191)
file = String.new
IO.foreach("lighter.jpg") do |line|
  file += line.chomp
end

server.send(file,0)

It works for a bit, then I get this error:

server.rb:7:in `accept': closed stream (IOError)
        from server.rb:7

The file sizes are nearly identical, I'm off by 479 bytes:

ynadji@onizuka:file_transfer$ du -b * 122753 lighter.jpg
122274 omgnew.jpg

Any ideas? I could be doing this entirely wrong, searching didn't yield any helpful results, so I figured I'd turn here. I was reading around with Array#pack and String#unpack which seems to be heading in the right direction, but I'm completely lost :P.

Thanks!

Yacin Nadji

Yacin Nadji wrote:

Hello Ruby Gurus!

My friend and I are writing a chat/IM client in Ruby. It's nothing
special, but it's helping us learn the language, especially the lower
level networking parts really well and I'm thoroughly enjoying the
project so far. I thought implementing file transfers would be pretty
nifty, but I'm running into some problems. I did a simple copy by
reading the file (a picture) and adding the lines to a string, and
writing that string out to a new file:

a = String.new

IO.foreach("lighter.jpg") do |line|
  a += line
end

This approach is quite inefficient in two ways:

- you use + for string concatenation which constantly creates new objects
and throws old ones away. Better use <<

- You need to keep the whole file in mem while with a streaming approach
(reading and writing a chunk at a time only) you can deal with arbitrary
sized files without worrying about memory.

file = File.open("new.jpg","w")

You should use mode "wb" - even if on Linux.

file.write(a)
file.close

And it worked swimmingly, however, when I tried to do this over a
TCPClient/Server:

server.rb

require 'socket'
port = 9191
file = File.open("omgnew.jpg","w+")

"wb" again...

server = TCPServer.new('localhost', port)
while session = server.accept
  file.write(session.gets)

Better use #read and #write instead of gets!

  server.close
  file.close
end

client.rb

require 'socket'

server = TCPSocket.new('localhost',9191)

You want TCPServer here.

file = String.new
IO.foreach("lighter.jpg") do |line|
  file += line.chomp
end

# untested
srv = TCPServer.new('localhost',9191)

while ( sess = srv.accept )
  Thread.new(sess) do |session|
   File.open("lighter.jpg", "rb") |io|
     session.write(io.read(1024))
   end
  end
end

server.send(file,0)

It works for a bit, then I get this error:

server.rb:7:in `accept': closed stream (IOError)
        from server.rb:7

The file sizes are nearly identical, I'm off by 479 bytes:

ynadji@onizuka:file_transfer$ du -b *
122753 lighter.jpg
122274 omgnew.jpg

Any ideas? I could be doing this entirely wrong, searching didn't
yield any helpful results, so I figured I'd turn here. I was reading
around with Array#pack and String#unpack which seems to be heading in
the right direction, but I'm completely lost :P.

Hope I could give some valuable hints.

Kind regards

    robert

try deleting the .chomp. Jpg's aren't really line oriented anyway. Also if you are on windows not opening the file in binary mode will wreak also sorts of havoc. As an alternative try this:

a = File.open("lighter.jpg", "rb") { |f| f.read }

···

On Feb 28, 2006, at 3:52 AM, Yacin Nadji wrote:

server = TCPSocket.new('localhost',9191)
file = String.new
IO.foreach("lighter.jpg") do |line|
file += line.chomp
end