[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Garbage bytes when reading from socket

yuri.leikind

6/26/2006 11:29:00 PM

Hi all,

I am using Ruby to write a simple client program that write some bytes
to a tcp server and then reads bytes.

I have a working version in Java and Perl.

With the Ruby version I have extremely strange behavior - there are
redundant bytes.

It looks like where the Perl and Java client output is 0D 0A, my Ruby
client has 0D 0D 0A. (the server can send both binary and text data,
but it will mostly be used for binary data). The requests sent from all
clients are identical, I checked it many times.

In Perl bytes from the socket are read like this:

while($nr = read($maryDataSocket, $buf, 100000)) {
print STDOUT $buf
or die "Write error on stdout";
}

I do it like this:

while out = maryDataSocket.read(100000)
f.write(out)
end

And yes, before that I do

maryDataSocket.binmode()

bit that doesn't help.

What's wrong?

I use Ruby for Windows (have to :-( ) , version 1.8.2-15

There are some other really weird and frustrating things all related to
IO and \r and \n, but well, I just want to solve this problem. Hell, I
just want to read some bytes from the socket the way the are!

Thank you

Best regards,
Yuri Leikind

6 Answers

Robert Klemme

6/27/2006 7:17:00 AM

0

yuri.leikind@gmail.com wrote:
> Hi all,
>
> I am using Ruby to write a simple client program that write some bytes
> to a tcp server and then reads bytes.
>
> I have a working version in Java and Perl.
>
> With the Ruby version I have extremely strange behavior - there are
> redundant bytes.
>
> It looks like where the Perl and Java client output is 0D 0A, my Ruby
> client has 0D 0D 0A. (the server can send both binary and text data,
> but it will mostly be used for binary data). The requests sent from all
> clients are identical, I checked it many times.
>
> In Perl bytes from the socket are read like this:
>
> while($nr = read($maryDataSocket, $buf, 100000)) {
> print STDOUT $buf
> or die "Write error on stdout";
> }
>
> I do it like this:
>
> while out = maryDataSocket.read(100000)
> f.write(out)
> end
>
> And yes, before that I do
>
> maryDataSocket.binmode()
>
> bit that doesn't help.
>
> What's wrong?
>
> I use Ruby for Windows (have to :-( ) , version 1.8.2-15
>
> There are some other really weird and frustrating things all related to
> IO and \r and \n, but well, I just want to solve this problem. Hell, I
> just want to read some bytes from the socket the way the are!

I'm afraid this is a bit too few information. Are you sure the server
doesn't actually write 0d0d0a and your Perl client just discards the
first 0d - either during reading or printing? Personally I'd try to use
a smaller buffer size - something like 4096. Not that I expect it to
solve your issue but in multithreaded environments it can make a difference.

Other than that, I'd suggest you post a bit more code. You could also
write a simplistic server in Ruby using TCPServer (test with writing
"0d0d0a" and "0d0a") and test both of your scripts against it. HTH

Kind regards

robert

yuri.leikind

6/27/2006 12:08:00 PM

0

> I'm afraid this is a bit too few information.

Mayby you are right

> Are you sure the server
> doesn't actually write 0d0d0a and your Perl client just discards the
> first 0d - either during reading or printing?

Absolutely. The thing is that the output is actually a wav file. The
perl client produces a valid wav file while the ruby client doesn't.

> Personally I'd try to use
> a smaller buffer size - something like 4096.

Done it. No effect.

> Other than that, I'd suggest you post a bit more code. You could also
> write a simplistic server in Ruby using TCPServer (test with writing
> "0d0d0a" and "0d0a") and test both of your scripts against it. HTH


Ok. The server is actually a text-to-speech system and it is accessible
in the Internet.

I have simplified both the perl and the ruby client as much as possible
and you can find them below. The algorythm is simple - you open a
socket, write a command and read an id. The open a socket again, write
the id and some natural text message (in case of this publicly
available server the language is german).


=== PERL ===
#!/usr/bin/env perl

use IO::Socket;

$host = "cling.dfki.uni-sb.de";
#$host = "localhost";

$maryInfoSocket = IO::Socket::INET->new(Proto => "tcp",
PeerAddr => $host,
PeerPort => 59125);
$maryInfoSocket->autoflush(1);

print $maryInfoSocket "MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE";
#print $maryInfoSocket "MARY IN=TEXT_EN OUT=RAWMARYXML"; # this will
result in text output
print $maryInfoSocket "\015\012";

$id = <$maryInfoSocket>;
chomp $id; chomp $id;

$maryDataSocket = IO::Socket::INET->new(Proto => "tcp",
PeerAddr => $host,
PeerPort => 59125);
print $maryDataSocket $id, "\015\012";

#print $maryDataSocket "Hello world";
print $maryDataSocket "Hallo Welt";

print $maryDataSocket "\015\012";

shutdown($maryDataSocket, 1);

open(OUT, ">out.pl.wav");
while($nr = read($maryDataSocket, $buf, 4096)) {
print OUT $buf;
}

===========

=== RUBY ===

#!/usr/bin/env ruby

require 'socket'

host = "cling.dfki.uni-sb.de";
#host = "localhost";

maryInfoSocket = TCPSocket.new(host, 59125)
maryInfoSocket.binmode()

maryInfoSocket.write("MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE")
#maryInfoSocket.write("MARY IN=TEXT_EN OUT=RAWMARYXML") # this will
result in text output

maryInfoSocket.write "\015\012"
maryInfoSocket.flush

id = maryInfoSocket.gets

id.chomp!

maryDataSocket = TCPSocket.new(host, 59125)
maryDataSocket.binmode()

maryDataSocket.write id + "\015\012"
maryDataSocket.flush

#maryDataSocket.write "Hello world" + "\015\012"
maryDataSocket.write "Hallo Welt" + "\015\012"

maryDataSocket.flush
maryDataSocket.close_write


File.open("out.rb.wav", "w"){|f|
while out = maryDataSocket.read(4096)
f.write(out)
end
}

===========

What am I missing here? Why are the results different?

Thank you!

Best regards,
Yuri Leikind

Robert Klemme

6/27/2006 2:04:00 PM

0

yuri.leikind@gmail.com wrote:
>> I'm afraid this is a bit too few information.
>
> Mayby you are right
>
>> Are you sure the server
>> doesn't actually write 0d0d0a and your Perl client just discards the
>> first 0d - either during reading or printing?
>
> Absolutely. The thing is that the output is actually a wav file. The
> perl client produces a valid wav file while the ruby client doesn't.
>
>> Personally I'd try to use
>> a smaller buffer size - something like 4096.
>
> Done it. No effect.

As I said, I don't expect that to cure the issue. :-)

>> Other than that, I'd suggest you post a bit more code. You could also
>> write a simplistic server in Ruby using TCPServer (test with writing
>> "0d0d0a" and "0d0a") and test both of your scripts against it. HTH
>
>
> Ok. The server is actually a text-to-speech system and it is accessible
> in the Internet.
>
> I have simplified both the perl and the ruby client as much as possible
> and you can find them below. The algorythm is simple - you open a
> socket, write a command and read an id. The open a socket again, write
> the id and some natural text message (in case of this publicly
> available server the language is german).
>
>
> === PERL ===
> #!/usr/bin/env perl
>
> use IO::Socket;
>
> $host = "cling.dfki.uni-sb.de";
> #$host = "localhost";
>
> $maryInfoSocket = IO::Socket::INET->new(Proto => "tcp",
> PeerAddr => $host,
> PeerPort => 59125);
> $maryInfoSocket->autoflush(1);
>
> print $maryInfoSocket "MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE";
> #print $maryInfoSocket "MARY IN=TEXT_EN OUT=RAWMARYXML"; # this will
> result in text output
> print $maryInfoSocket "\015\012";
>
> $id = <$maryInfoSocket>;
> chomp $id; chomp $id;
>
> $maryDataSocket = IO::Socket::INET->new(Proto => "tcp",
> PeerAddr => $host,
> PeerPort => 59125);
> print $maryDataSocket $id, "\015\012";
>
> #print $maryDataSocket "Hello world";
> print $maryDataSocket "Hallo Welt";
>
> print $maryDataSocket "\015\012";
>
> shutdown($maryDataSocket, 1);
>
> open(OUT, ">out.pl.wav");
> while($nr = read($maryDataSocket, $buf, 4096)) {
> print OUT $buf;
> }
>
> ===========
>
> === RUBY ===
>
> #!/usr/bin/env ruby
>
> require 'socket'
>
> host = "cling.dfki.uni-sb.de";
> #host = "localhost";
>
> maryInfoSocket = TCPSocket.new(host, 59125)
> maryInfoSocket.binmode()
>
> maryInfoSocket.write("MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE")
> #maryInfoSocket.write("MARY IN=TEXT_EN OUT=RAWMARYXML") # this will
> result in text output
>
> maryInfoSocket.write "\015\012"
> maryInfoSocket.flush
>
> id = maryInfoSocket.gets
>
> id.chomp!
>
> maryDataSocket = TCPSocket.new(host, 59125)
> maryDataSocket.binmode()

I don't think there is a binmode for sockets - doesn't really seem to
make sense. IMHO sockets are *always* binary.

> maryDataSocket.write id + "\015\012"
> maryDataSocket.flush
>
> #maryDataSocket.write "Hello world" + "\015\012"
> maryDataSocket.write "Hallo Welt" + "\015\012"
>
> maryDataSocket.flush
> maryDataSocket.close_write
>
>
> File.open("out.rb.wav", "w"){|f|

Use file mode "wb" regardless of operating system.

> while out = maryDataSocket.read(4096)
> f.write(out)
> end
> }
>
> ===========
>
> What am I missing here? Why are the results different?

Another remark: I'd use the block form of TCPSocket.open, like in

TCPSocket.open(host, 59125) do |sock|
...
end

Kind regards

robert

yuri.leikind

6/27/2006 2:33:00 PM

0

Thanks a lot!


Robert Klemme wrote:
> yuri.leikind@gmail.com wrote:
> >> I'm afraid this is a bit too few information.
> >
> > Mayby you are right
> >
> >> Are you sure the server
> >> doesn't actually write 0d0d0a and your Perl client just discards the
> >> first 0d - either during reading or printing?
> >
> > Absolutely. The thing is that the output is actually a wav file. The
> > perl client produces a valid wav file while the ruby client doesn't.
> >
> >> Personally I'd try to use
> >> a smaller buffer size - something like 4096.
> >
> > Done it. No effect.
>
> As I said, I don't expect that to cure the issue. :-)
>
> >> Other than that, I'd suggest you post a bit more code. You could also
> >> write a simplistic server in Ruby using TCPServer (test with writing
> >> "0d0d0a" and "0d0a") and test both of your scripts against it. HTH
> >
> >
> > Ok. The server is actually a text-to-speech system and it is accessible
> > in the Internet.
> >
> > I have simplified both the perl and the ruby client as much as possible
> > and you can find them below. The algorythm is simple - you open a
> > socket, write a command and read an id. The open a socket again, write
> > the id and some natural text message (in case of this publicly
> > available server the language is german).
> >
> >
> > === PERL ===
> > #!/usr/bin/env perl
> >
> > use IO::Socket;
> >
> > $host = "cling.dfki.uni-sb.de";
> > #$host = "localhost";
> >
> > $maryInfoSocket = IO::Socket::INET->new(Proto => "tcp",
> > PeerAddr => $host,
> > PeerPort => 59125);
> > $maryInfoSocket->autoflush(1);
> >
> > print $maryInfoSocket "MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE";
> > #print $maryInfoSocket "MARY IN=TEXT_EN OUT=RAWMARYXML"; # this will
> > result in text output
> > print $maryInfoSocket "\015\012";
> >
> > $id = <$maryInfoSocket>;
> > chomp $id; chomp $id;
> >
> > $maryDataSocket = IO::Socket::INET->new(Proto => "tcp",
> > PeerAddr => $host,
> > PeerPort => 59125);
> > print $maryDataSocket $id, "\015\012";
> >
> > #print $maryDataSocket "Hello world";
> > print $maryDataSocket "Hallo Welt";
> >
> > print $maryDataSocket "\015\012";
> >
> > shutdown($maryDataSocket, 1);
> >
> > open(OUT, ">out.pl.wav");
> > while($nr = read($maryDataSocket, $buf, 4096)) {
> > print OUT $buf;
> > }
> >
> > ===========
> >
> > === RUBY ===
> >
> > #!/usr/bin/env ruby
> >
> > require 'socket'
> >
> > host = "cling.dfki.uni-sb.de";
> > #host = "localhost";
> >
> > maryInfoSocket = TCPSocket.new(host, 59125)
> > maryInfoSocket.binmode()
> >
> > maryInfoSocket.write("MARY IN=TEXT_EN OUT=AUDIO AUDIO=WAVE")
> > #maryInfoSocket.write("MARY IN=TEXT_EN OUT=RAWMARYXML") # this will
> > result in text output
> >
> > maryInfoSocket.write "\015\012"
> > maryInfoSocket.flush
> >
> > id = maryInfoSocket.gets
> >
> > id.chomp!
> >
> > maryDataSocket = TCPSocket.new(host, 59125)
> > maryDataSocket.binmode()
>
> I don't think there is a binmode for sockets - doesn't really seem to
> make sense. IMHO sockets are *always* binary.
>
> > maryDataSocket.write id + "\015\012"
> > maryDataSocket.flush
> >
> > #maryDataSocket.write "Hello world" + "\015\012"
> > maryDataSocket.write "Hallo Welt" + "\015\012"
> >
> > maryDataSocket.flush
> > maryDataSocket.close_write
> >
> >
> > File.open("out.rb.wav", "w"){|f|
>
> Use file mode "wb" regardless of operating system.
>
> > while out = maryDataSocket.read(4096)
> > f.write(out)
> > end
> > }
> >
> > ===========
> >
> > What am I missing here? Why are the results different?
>
> Another remark: I'd use the block form of TCPSocket.open, like in
>
> TCPSocket.open(host, 59125) do |sock|
> ...
> end
>
> Kind regards
>
> robert

Robert Klemme

6/27/2006 2:50:00 PM

0

yuri.leikind@gmail.com wrote:
> Thanks a lot!

So it the issue resolved?

robert

yuri.leikind

6/27/2006 9:00:00 PM

0

> So it the issue resolved?

Yes! The problem was not in the socket, but in file opening mode.

Thank a lot!

Yuri