Puzzled about Ruby's behaviour re. closed sockets

E

Emmanuel Gaillot

Everyone,

I'd like to write a test that ensures a Server application correctly
handles closed client connections -- more specifically: I want to set
up a TCPServer, then a client, then close the client, then attempt to
write on the client Connection from server side -- and make sure no
Error gets fired.

To my great surprise, the test doesn't behave in any predictible way
-- sometimes it passes, sometimes it fails.

I've written a piece of code that illustrates it:
=============
require 'socket'

consecutive_puts_to_attempt = 1
ok_counter = 0
error_counter = 0

10000.times do
server = TCPServer.open '127.0.0.1', 4807
client = TCPSocket.open '127.0.0.1', 4807
connection = server.accept
client.close

begin
consecutive_puts_to_attempt.times {connection.puts "Hello!"}
ok_counter += 1
rescue
error_counter += 1
end
server.close
end

puts "(Unexpectedly) passed #{ok_counter} times;"
puts "(correctly) failed #{error_counter} times."
=============

Statistically, this piece of code unexpectedly passes with no raised
error about 98% of the time. Errors are Errno::EPIPE and
Errno::ECONNRESET

When I fiddle with consecutive_puts_to_attempt value, the number of
expected raised errors changes --

puts attempts chances of raised error
1 2%
2 98%
3 98.5%
4 99%


Here is my environment:
ruby -v
ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.10.1]

Any idea of what's going on?
Any suggestion about how I could make this piece of code predictible?
-- Emmanuel.
 
R

Robert Klemme

------=_Part_26790_14024829.1185782262237
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

2007/7/29 said:
I'd like to write a test that ensures a Server application correctly
handles closed client connections -- more specifically: I want to set
up a TCPServer, then a client, then close the client, then attempt to
write on the client Connection from server side -- and make sure no
Error gets fired.

To my great surprise, the test doesn't behave in any predictible way
-- sometimes it passes, sometimes it fails.
Any idea of what's going on?
Any suggestion about how I could make this piece of code predictible?

I guess it's a combination of timing and buffering issue. With a
modified version I get

RKlemme@padrklemme1 ~
$ ruby ruby/socket-test-1.rb
(Unexpectedly) passed 2 times;
{Errno::ECONNABORTED=>998}

(see attachment)

Kind regards

robert

------=_Part_26790_14024829.1185782262237
Content-Type: application/x-ruby; name="socket-test-1.rb"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="socket-test-1.rb"
X-Attachment-Id: f_f4qo4qxd

cmVxdWlyZSAnc29ja2V0JwpyZXF1aXJlICdwcCcKCmNvbnNlY3V0aXZlX3B1dHNfdG9fYXR0ZW1w
dCA9IDEKb2tfY291bnRlciA9IDAKZXJyb3JfY291bnRlciA9IEhhc2gubmV3IDAKc2VydmVyID0g
VENQU2VydmVyLm9wZW4gJzEyNy4wLjAuMScsIDQ4MDcKCjEwMDAudGltZXMgZG8gfGl8CiAgIyBw
dXRzICJydW4gI3tpfSIKICAgIGNsaWVudCA9IFRDUFNvY2tldC5vcGVuICcxMjcuMC4wLjEnLCA0
ODA3CiAgICBjb25uZWN0aW9uID0gc2VydmVyLmFjY2VwdAogICAgc2xlZXAgMC4xCiAgICBjbGll
bnQuY2xvc2UKCiAgICBiZWdpbgogICAgICBjb25zZWN1dGl2ZV9wdXRzX3RvX2F0dGVtcHQudGlt
ZXMge2Nvbm5lY3Rpb24ucHV0cyAiSGVsbG8hIn0KICAgICAgb2tfY291bnRlciArPSAxCiAgICBy
ZXNjdWUgRXhjZXB0aW9uID0+IGUKICAgICAgZXJyb3JfY291bnRlcltlLmNsYXNzXSArPSAxCiAg
ICBlbmQKZW5kCnNlcnZlci5jbG9zZQoKcHV0cyAiKFVuZXhwZWN0ZWRseSkgcGFzc2VkICN7b2tf
Y291bnRlcn0gdGltZXM7IgpwcCBlcnJvcl9jb3VudGVyCg==
------=_Part_26790_14024829.1185782262237--
 
E

Emmanuel Gaillot

Robert,

Thanks for your answer.
With a modified version I get

(Unexpectedly) passed 2 times;
{Errno::ECONNABORTED=>998}

I've tried your modified version. Here is a typical output when
attempting once to write in the closed pipe :
----------------------------------------------
(Unexpectedly) passed 960 times;
{Errno::EPIPE=>38, Errno::ECONNRESET=>2}
----------------------------------------------

.... this to be compared with typical output when attempting to write
6th times in a row in the closed pipe :
----------------------------------------------
(Unexpectedly) passed 4 times;
{Errno::EPIPE=>987, Errno::ECONNRESET=>9}
----------------------------------------------

Strangely enough, I don't seem to get any Errno::ECONNABORTED ever.

I guess it's a combination of timing and buffering issue.

I've reached the same conclusion -- which brings me to the question:
what can I do to make the combination of timing and buffering
predictible? Or how may I get around it?

-- Emmanuel.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,740
Latest member
AdolphBig6

Latest Threads

Top