Socket problem

Hi,

We're having problems with the standard Socket module with Ruby. It has
been alleged that this might be a C Runtime issue. But this seems
unlikely in light of the fact that other ports on the same platform --
notably Perl, and perhaps also Python -- have working sockets, also
implemented on top of the same C Runtime.

Can someone shed some light on what may be going on?

Here is a failing case, as we first reported the problem:

client.rb:
        require 'socket'
        s=TCPSocket.new("localhost", ARGV[0])
        s.puts("test\r\n")
        puts s.gets
        s.puts("Blah, blah\r\n")
        puts s.gets
        s.close

server.rb:
        require 'socket'
        gs = TCPServer.open(0)
        printf("server is on port %d\n", gs.addr[1])
        s=gs.accept
        line = s.gets
        puts("Got line: #{line}")
        s.puts(line.upcase)
        bl = s.gets
        puts ("Got str2: #{bl}")
        s.puts(bl.upcase)
        s.close

On Linux (ruby 1.8.2), this gave the following output, as expected:
     (client side)
        TEST
        BLAH, BLAH
     (server side)
        server is on port 40050
        Got line: test
        Got str2: Blah, blah

On OpenVMS (ruby 1.8.1), this surprisingly gave the following output:
     (client side)
        test
        test
     (server side)
        server is on port 49379
        Got line: test
        Got str2: test

We tried varying the test by changing our puts to write on the client
side, but the test results were the same on both platforms.

Thanks,
Ben Armstrong

···

--
      Ben Armstrong -. Medianet Development Group,
      BArmstrong@dymaxion.ca `-. Dymaxion Research Limited
      <URL: http://www.dymaxion.ca/> `- Halifax, Nova Scotia, Canada

Hi,

We're having problems with the standard Socket module with Ruby. It has
been alleged that this might be a C Runtime issue. But this seems
unlikely in light of the fact that other ports on the same platform --
notably Perl, and perhaps also Python -- have working sockets, also
implemented on top of the same C Runtime.

i'm guessing you are using 'print' in the perl version and, therefore, not
sending a bunch of extra newlines as the code below is doing do to 'puts'?
not sure why that'd make a difference but...

-a

Can someone shed some light on what may be going on?

Here is a failing case, as we first reported the problem:

client.rb:
       require 'socket'
       s=TCPSocket.new("localhost", ARGV[0])
       s.puts("test\r\n")
       puts s.gets
       s.puts("Blah, blah\r\n")
       puts s.gets
       s.close

server.rb:
       require 'socket'
       gs = TCPServer.open(0)
       printf("server is on port %d\n", gs.addr[1])
       s=gs.accept
       line = s.gets
       puts("Got line: #{line}")
       s.puts(line.upcase)
       bl = s.gets
       puts ("Got str2: #{bl}")
       s.puts(bl.upcase)
       s.close

On Linux (ruby 1.8.2), this gave the following output, as expected:
    (client side)
       TEST
       BLAH, BLAH
    (server side)
       server is on port 40050
       Got line: test
       Got str2: Blah, blah

On OpenVMS (ruby 1.8.1), this surprisingly gave the following output:
    (client side)
       test
    (server side)
       server is on port 49379
       Got line: test
       Got str2: test

We tried varying the test by changing our puts to write on the client
side, but the test results were the same on both platforms.

Thanks,
Ben Armstrong
--
     Ben Armstrong -. Medianet Development Group,
     BArmstrong@dymaxion.ca `-. Dymaxion Research Limited
     <URL: http://www.dymaxion.ca/&gt; `- Halifax, Nova Scotia, Canada

-a

···

On Fri, 5 Nov 2004, Ben Armstrong wrote:
--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
When you do something, you should burn yourself completely, like a good
bonfire, leaving no trace of yourself. --Shunryu Suzuki

===============================================================================

We're having problems with the standard Socket module with Ruby.

Try to use IO#sync=

Guy Decoux

I guess the factor we probably didn't consider is that although these
languages use the same C Runtime, they may not all use it in the same way,
so now my question is, given the following findings, how can our Ruby port
be fixed so that it behaves like Perl?

What I've found out is that if I follow each 'gets' and 'puts' with
'fsync', the output from my test is as expected on OpenVMS:

-- server.rb --
        require 'socket'
        gs = TCPServer.open(0)
        printf("server is on port %d\n", gs.addr[1])
        s=gs.accept
        line = s.gets
        s.fsync
        puts("Got line: #{line}")
        s.puts(line.upcase)
        s.fsync
        bl = s.gets
        s.fsync
        puts ("Got str2: #{bl}")
        s.puts(bl.upcase)
        s.fsync
        s.close
-- end server.rb --

-- client.rb --
        require 'socket'
        s=TCPSocket.new("localhost", ARGV[0])
        s.puts("test\r\n")
        s.fsync
        puts s.gets
        s.fsync
        s.puts("Blah, blah\r\n")
        s.fsync
        puts s.gets
        s.fsync
        s.close
-- end client.rb --

Ruby's IO module sets the buffer to _IOFBF via setvbuf. I don't see any
such construct in the Perl source. Is there a reason Ruby is doing this
and Perl isn't?

Ben

···

On Fri, 05 Nov 2004 19:29:16 +0000, Ben Armstrong wrote:

It has
been alleged that this might be a C Runtime issue. But this seems
unlikely in light of the fact that other ports on the same platform --
notably Perl, and perhaps also Python -- have working sockets, also
implemented on top of the same C Runtime.

--
      Ben Armstrong -. Medianet Development Group,
      BArmstrong@dymaxion.ca `-. Dymaxion Research Limited
      <URL: http://www.dymaxion.ca/&gt; `- Halifax, Nova Scotia, Canada

That didn't help. Besides, sync is set to true by default.

However, I did pull out a packet sniffer and found out something very
interesting. It appears that for each operation, the old contents of the
buffer is not being overwritten! Instead, it just keeps getting appended
to.

Thus, when I send the first line, I am sending "test\r\n". The server
receives this, and writes back "test\r\n\TEST\r\n". Since my client only
does a gets on the one line expected, it displays "test\r\n".

My "fixed" versions (not really fixed, but demonstrate the problem
clearly) are as follows:

-- client.rb --
        require 'socket'
        s=TCPSocket.new("localhost", ARGV[0])
        s.puts("test\r\n")
        printf("garbage: %s",s.gets)
        puts s.gets
        s.puts("Blah, blah\r\n")
        printf("garbage: %s",s.gets)
        printf("garbage: %s",s.gets)
        printf("garbage: %s",s.gets)
        puts s.gets
        s.close
-- end client.rb --

-- server.rb --
        require 'socket'
        gs = TCPServer.open(0)
        printf("server is on port %d\n", gs.addr[1])
        s=gs.accept
        line = s.gets
        s.flush
        puts("Got line: #{line}")
        s.puts(line.upcase)
        bl = s.gets
        puts ("Got str2 (garbage): #{bl}")
        bl = s.gets
        puts ("Got str3 (garbage): #{bl}")
        bl = s.gets
        puts ("Got str4: #{bl}")
        s.puts(bl.upcase)
        s.close
-- end server.rb --

The output on the server side is:

server is on port 50507
Got line: test
Got str2 (garbage): test
Got str3 (garbage): TEST
Got str4: Blah, blah

The output on the client side is:

garbage: test
TEST
garbage: test
garbage: TEST
garbage: Blah, blah
BLAH, BLAH

Ignoring the lines marked "garbage" we can now see the intended output:

TEST
BLAH, BLAH

How strange, eh? OK, how do I discard the buffer between operations? Or
do I need the developer of the port to help me with this?

Ben

···

On Sat, 06 Nov 2004 21:32:19 +0900, ts wrote:

> We're having problems with the standard Socket module with Ruby.

Try to use IO#sync=

--
      Ben Armstrong -. Medianet Development Group,
      BArmstrong@dymaxion.ca `-. Dymaxion Research Limited
      <URL: http://www.dymaxion.ca/&gt; `- Halifax, Nova Scotia, Canada

Hi Ben. I might be completely wrong with this one, but have you tried
removing the "\r\n" at the end of the messages? Doesn't #puts add the
newline for you. I believe that could be it.

Regards,
Ed

···

On Tue, 9 Nov 2004 05:23:34 +0900, Ben Armstrong <ben@bgpc.dymaxion.ca> wrote:

On Sat, 06 Nov 2004 21:32:19 +0900, ts wrote:

>
> > We're having problems with the standard Socket module with Ruby.
>
> Try to use IO#sync=

That didn't help. Besides, sync is set to true by default.

However, I did pull out a packet sniffer and found out something very
interesting. It appears that for each operation, the old contents of the
buffer is not being overwritten! Instead, it just keeps getting appended
to.

Thus, when I send the first line, I am sending "test\r\n". The server
receives this, and writes back "test\r\n\TEST\r\n". Since my client only
does a gets on the one line expected, it displays "test\r\n".

--
Despite the surge of power you feel upon learning Ruby,
resist the urge to trip others or slap them in the bald head.
DO NOT LORD YOUR RUBYNESS OVER OTHERS!

I'm reporting what I'm seeing with the packet sniffer. If what you say is
true, I would see "\r\n\r\n". But that's not what's getting sent. I only
see a single "\r\n" pair at the end of each line.

In earlier tests, before I started working on the problem, I understand we
tried various different variations: puts vs. write, newline, no newline,
etc. None of this affected the issue with the buffer not being overwritten
with the new data.

Ben

···

On Tue, 09 Nov 2004 08:13:03 +0900, Edgardo Hames wrote:

Hi Ben. I might be completely wrong with this one, but have you tried
removing the "\r\n" at the end of the messages? Doesn't #puts add the
newline for you. I believe that could be it.

--
      Ben Armstrong -. Medianet Development Group,
      BArmstrong@dymaxion.ca `-. Dymaxion Research Limited
      <URL: http://www.dymaxion.ca/&gt; `- Halifax, Nova Scotia, Canada