Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket read does not "returns $bytes bytes". #3020

Closed
p6rt opened this issue Jan 4, 2013 · 8 comments
Closed

Socket read does not "returns $bytes bytes". #3020

p6rt opened this issue Jan 4, 2013 · 8 comments

Comments

@p6rt
Copy link

p6rt commented Jan 4, 2013

Migrated from rt.perl.org#116288 (status was 'resolved')

Searchable as RT116288$

@p6rt
Copy link
Author

p6rt commented Jan 4, 2013

From @bbkr

There was socket behavior change between Rakudo 2012.11 and 2012.12 that caused failure of many modules.

It is discussed here​: parrot/parrot#909

Current Perl 6 spec says that read($bytes) "Reads and returns $bytes bytes from the handle". But after change it returns only one chunk if desired $bytes count is higher than chunk size.

To reproduce​:

* run following simple server that returns 2KB of data

perl6 -e 'my $listener = IO​::Socket​::INET.new( localhost => "", localport => 8080, :listen ); while my $connection = $listener.accept( ) { $connection.send( "x" x 2048 ); $connection.close( ); }'

* and then try to read them

2012.11 is getting whole 2KB​:
$ perl6 -e 'my $client = IO​::Socket​::INET.new( host => "localhost", port => 8080 ); my $buf = $client.read(2048); $buf.bytes.say'
2048

while 2012.12 is getting only 256 bytes
$ perl6 -e 'my $client = IO​::Socket​::INET.new( host => "localhost", port => 8080 ); my $buf = $client.read(2048); $buf.bytes.say'
256

Non-continous data flow is also broken​:

* run following simple server that returns 8 bytes of data in 2 byte chunks

perl6 -e 'my $listener = IO​::Socket​::INET.new( localhost => "", localport => 8080, :listen ); while my $connection = $listener.accept( ) { for ^4 { $connection.send( "xx" ); sleep 1;}; $connection.close( ); }'

2012.11 waits for desired amount of data to be available and returns 8 bytes

$ time perl6 -e 'my $client = IO​::Socket​::INET.new( host => "localhost", port => 8080 ); my $buf = $client.read(8); $buf.bytes.say'
8
real 0m3.563s # correct time, 3 sleeps were made before 8 bytes were available
user 0m0.417s
sys 0m0.135s

while 2012.12 gets only first batch available on socket

$ perl6 -e 'my $client = IO​::Socket​::INET.new( host => "localhost", port => 8080 ); my $buf = $client.read(8); $buf.bytes.say'
2

@p6rt
Copy link
Author

p6rt commented Jan 4, 2013

From @bbkr

<rurban> bbkr​: Looks like parrot wants to follow the established POSIX and perl5 behaviour.
The specs need to changed.
<rurban> socket.read returns max len bytes
<rurban> but not guaranteed len bytes
<rurban> http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html
<rurban> The size argument is for languages which do not malloc buffers by themselves. The
receiving buffer must be preallocated and the recv() function writes into it.
* bitonic has quit (Ping timeout​: 252 seconds)
<rurban> But I'm not sure what the high-level parrot socket.read() method should do, since we
provide the low-level recv() method also.

So for now there is discrepancy between Rakudo behavior and Perl 6 spec. Either wrapper
around parrot behavior should be created to match current spec. Or spec should change to
follow POSIX way - which is discussed here​: Raku/old-design-docs#26 .

@p6rt
Copy link
Author

p6rt commented Jan 4, 2013

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Jan 4, 2013

From @FROGGS

If we need to patch rakudo I would recommend to keep simple things
simple. So for a simple app, rakudo should collect and buffer the
desired data. If someone is aware of the chunks and wants to handle it,
one has to supply a parameter.

@p6rt
Copy link
Author

p6rt commented Jan 5, 2013

From @FROGGS

out of the today's irclog​:

<supernovus> Hmm, HTTP​::Easy depends on the get() method working
properly. Oh, also, it seems if you do IO​::Socket.read() and there's no
more data to send, instead of returning nothing, it just hangs. This
makes writing while my $data = $socket.read(256) { ... } not work at all...

So if somebody doesnt know the chunk size, (s)he will be unable to use
read() at all. _If_ you know the chunk size you can say​:

  last if $data < $chunk-size

But what if other implementations like niecza or jakudo will have a
different chunk size? How to write reliable code?

@p6rt
Copy link
Author

p6rt commented Jan 10, 2013

From @moritz

On Sat Jan 05 01​:10​:17 2013, FROGGS.de wrote​:

So if somebody doesnt know the chunk size, (s)he will be unable to use
read() at all. _If_ you know the chunk size you can say​:

last if $data < $chunk-size

If one doesn't know how much data to expect, one simply uses .recv.
Currently there's no version of .recv that returns a Buf (only Str), but
providing one is the proper fix.

@p6rt
Copy link
Author

p6rt commented Nov 27, 2015

From @jnthn

On Thu Jan 10 04​:43​:32 2013, moritz wrote​:

On Sat Jan 05 01​:10​:17 2013, FROGGS.de wrote​:

So if somebody doesnt know the chunk size, (s)he will be unable to use
read() at all. _If_ you know the chunk size you can say​:

last if $data < $chunk-size

If one doesn't know how much data to expect, one simply uses .recv.
Currently there's no version of .recv that returns a Buf (only Str), but
providing one is the proper fix.

By now, things have been sorted out so that​:

* read will do repeated socket reads to get sufficient data to meet what was requested, unless the connection is closed in which case it can return less; it'll never return more

* recv will only ever do one actual recv on the socket, so if one read does not produce enough data, you'll just get a short result; the optional argument serves as an upper limit

And these days, recv has a :bin parameter.

Tests codifying this behavior in S32-io/socket-recv-vs-read.t.

@p6rt p6rt closed this as completed Nov 27, 2015
@p6rt
Copy link
Author

p6rt commented Nov 27, 2015

@jnthn - Status changed from 'open' to 'resolved'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant