Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Socket issue

Reply
Thread Tools

Socket issue

 
 
Marc Soda
Guest
Posts: n/a
 
      01-22-2007
Hey all,

While testing some edge cases in an app I came across a strange socket
issue. If I have a server that dies unexpectedly, and then try to
write to it from an already connected client, it doesn't raise an
exception until the next time I try to write it.

Example:

Server
---------
require 'socket'

include Socket::Constants

sock = Socket.new(AF_INET, SOCK_STREAM, 0)
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, true)
sockaddr = Socket.pack_sockaddr_in(7000, 'localhost')
sock.bind(sockaddr)
sock.listen(0)

client, client_sockaddr = sock.accept
print "Connected\n"
print ">>> #{client.readline}"
abort



Client
--------
require 'socket'
include Socket::Constants

$sock = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.pack_sockaddr_in(7000, 'localhost')
$sock.connect(sockaddr)

def send_msg
begin
$sock.write("Hello\n")
rescue StandardError => err
p err
end
end

puts "1"
send_msg
sleep 0.5
puts "2"
send_msg # Should error here.
sleep 0.5
puts "3"
send_msg

Any suggestions? I'm running on Linux, BTW.

Thanks,
Marc

 
Reply With Quote
 
 
 
 
gwtmp01@mac.com
Guest
Posts: n/a
 
      01-22-2007

On Jan 22, 2007, at 10:53 AM, Marc Soda wrote:
> Any suggestions? I'm running on Linux, BTW.


What you are seeing is in the nature of TCP.

After the connection succeeds your server shuts down *its* end of
the TCP session (i.e. it tells the client that it won't send any
more data). Since TCP is full duplex, the client-> server part of
the connection is still up and running as far as the client is
concerned.

Your first write stuffs the data in a buffer and returns (with no
error). Shortly thereafter the kernel decides to actually transmit
the data. The server responds with a RESET indicating that it will
no longer accept data on that TCP session. The error is noted by
the kernel and is reported to your client code on the *next* attempt
to write to the socket (which is now in an error state).

There is no one-to-one mapping of a write call on the socket to
data transmission on the wire for TCP due to buffering. This is
why the first write doesn't cause the transmit/detect/report of
the error.

Gary Wright




 
Reply With Quote
 
 
 
 
Marc Soda
Guest
Posts: n/a
 
      01-23-2007
On 1/22/07, http://www.velocityreviews.com/forums/(E-Mail Removed) <(E-Mail Removed)> wrote:
> What you are seeing is in the nature of TCP.
>
> After the connection succeeds your server shuts down *its* end of
> the TCP session (i.e. it tells the client that it won't send any
> more data). Since TCP is full duplex, the client-> server part of
> the connection is still up and running as far as the client is
> concerned.
>
> Your first write stuffs the data in a buffer and returns (with no
> error). Shortly thereafter the kernel decides to actually transmit
> the data. The server responds with a RESET indicating that it will
> no longer accept data on that TCP session. The error is noted by
> the kernel and is reported to your client code on the *next* attempt
> to write to the socket (which is now in an error state).
>
> There is no one-to-one mapping of a write call on the socket to
> data transmission on the wire for TCP due to buffering. This is
> why the first write doesn't cause the transmit/detect/report of
> the error.
>
> Gary Wright
>
>
>
>
>


Gary,

First, thanks for your answer. I agree with you, however, my
understanding was that after the client side kernel flushes it's
buffers from the second send(2) (the first send after the server dies)
the server would send a RST back. If I were to go about other
processing and not even touch the socket again I should still receive
and SIGPIPE. Is this not true?

Thanks for your time.
Marc

 
Reply With Quote
 
gwtmp01@mac.com
Guest
Posts: n/a
 
      01-23-2007

On Jan 22, 2007, at 10:59 PM, Marc Soda wrote:
> First, thanks for your answer. I agree with you, however, my
> understanding was that after the client side kernel flushes it's
> buffers from the second send(2) (the first send after the server dies)
> the server would send a RST back. If I were to go about other
> processing and not even touch the socket again I should still receive
> and SIGPIPE. Is this not true?


The SIGPIPE is sent when you attempt to write to the socket, not when
the kernel receives the RST. So in your example, the timeline looks
like:

client server
------------------------------
listen
connect
accept
abort
<-----------FIN
write
sleep
| 'hello' -------->
| <----------- RST
write: SIGPIPE


That is a pretty lame diagram but I hope it clarifies things.

FYI, this is a behavior of the underlying socket abstraction, not
something particular to Ruby.


Gary Wright



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: socket.unbind or socket.unlisten? - socket.error: (48, 'Addressalready in use') Steve Holden Python 1 02-03-2009 06:20 AM
Re: socket.unbind or socket.unlisten? - socket.error: (48, 'Addressalready in use') Steve Holden Python 0 02-01-2009 12:45 PM
Re: socket.unbind or socket.unlisten? - socket.error: (48, 'Addressalready in use') Laszlo Nagy Python 0 02-01-2009 07:37 AM
socket.unbind or socket.unlisten? - socket.error: (48, 'Addressalready in use') Laszlo Nagy Python 1 01-27-2009 05:05 PM
Re: socket.unbind or socket.unlisten? - socket.error: (48,'Address already in use') Jean-Paul Calderone Python 0 01-27-2009 01:41 PM



Advertisments