[Boost-users] Boost ASIO - SO_LINGER Socket option is not working

1,150 views
Skip to first unread message

Nick Aschberger

unread,
May 28, 2009, 10:42:04 PM5/28/09
to boost...@lists.boost.org
Hi All,

I have a situation where at termination of my program, I am closing my
socket, and then deleting the socket object. Note, we are using
non-asynchronous (blocking) accesses at this point, boost is version 1.36.

In some cases, the socket has had some data written to it, but that data
is never received by the connected client - because I destroy the socket
before the data is sent.

So, SO_LINGER is the socket option that is supposed to solve all my
worries (it should wait on close for any unsent data to be sent),
however I am using it and there is no effect. I presume because I'm
doing something wrong.

Here is my psuedo-code flow:

/* Creation of socket */
m_socket = new boost::asio::ip::tcp::socket(m_io_service);

/* Connect the socket with something like: */
acceptor.accept(*m_socket, error);

/* Set SO_LINGER option on connected socket */
boost::asio::socket_base::linger linger_op(true, 2000);
m_socket->set_option(linger_op);

/* program executes, does some stuff */

/* At termination */
// close the socket
m_socket->close();
delete(m_socket);


I experimented with m_socket->shutdown() instead of close, and it made
little difference. In fact, from the documentation it seems shutdown()
is the one I definitely don't want to call, as close() is supposed to
wait for data to be sent.

If anyone has some suggestions as to what would be correct, I would much
appreciate it.

cheers

Nick Aschberger

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Igor R

unread,
May 30, 2009, 1:17:41 PM5/30/09
to boost...@lists.boost.org
> I have a situation where at termination of my program, I am closing my
> socket, and then deleting the socket object. Note, we are using
> non-asynchronous (blocking) accesses at this point, boost is version 1.36.
>
> In some cases, the socket has had some data written to it, but that data is
> never received by the connected client - because I destroy the socket before
> the data is sent.
>
> So, SO_LINGER is the socket option that is supposed to solve all my worries
> (it should wait on close for any unsent data to be sent), however I am using
> it and there is no effect. I presume because I'm doing something wrong.

SO_LINGER is just forwarded as-is to the native socket API, so if it
doesn't work there's some problem with the socket.
What I couldn't understand from your description is whether you used
sync. or async. i/o, and from what thread (same as close() or some
other). Could you please clarify these points?

Nick Aschberger

unread,
May 31, 2009, 9:05:50 PM5/31/09
to boost...@lists.boost.org
Igor R wrote:
I have a situation where at termination of my program, I am closing my
socket, and then deleting the socket object. Note, we are using
non-asynchronous (blocking) accesses at this point, boost is version 1.36.

In some cases, the socket has had some data written to it, but that data is
never received by the connected client - because I destroy the socket before
the data is sent.

So, SO_LINGER is the socket option that is supposed to solve all my worries
(it should wait on close for any unsent data to be sent), however I am using
it and there is no effect. I presume because I'm doing something wrong.
    
SO_LINGER is just forwarded as-is to the native socket API, so if it
doesn't work there's some problem with the socket.
What I couldn't understand from your description is whether you used
sync. or async. i/o, and from what thread (same as close() or some
other). Could you please clarify these points?
Hi Igor,

There is only one thread in this program, and we are using sync (blocking) accesses.
So it is definately the same thread that writes some data on the socket and then deletes the socket.

Am I setting the property correctly on the socket? Does it need to be set on the acceptor or something instead/as well?

cheers

Nick

Igor R

unread,
Jun 2, 2009, 10:11:22 AM6/2/09
to boost...@lists.boost.org
> Am I setting the property correctly on the socket? Does it need to be set on
> the acceptor or something instead/as well?

I never user this option with asio, but it seems that your usage
complies with the asio reference.
To debug this issue, you can substitute asio send() call with the
appropriate native api. If the lingering still doesn't work, it's
probably not supported by your socket.

Zachary Turner

unread,
Jun 2, 2009, 10:41:36 AM6/2/09
to boost...@lists.boost.org
On Thu, May 28, 2009 at 9:42 PM, Nick Aschberger <nick.as...@astc-design.com> wrote:

I experimented with m_socket->shutdown() instead of close, and it made little difference. In fact, from the documentation it seems shutdown() is the one I definitely don't want to call, as close() is supposed to wait for data to be sent.

This is a common point of confusion with sockets programming.  Here is how it works according to my understanding.  Note that I know nothing of how boost sockets are implemented, the following applies specifically to the BSD socket interface, which means that by extension it should apply to boost sockets although I can't guarantee that.

1) shutdown() initiates a graceful termination sequence.  It never blocks, regardless of the value of SO_LINGER.  shutdown() specifically tells the kernel "I'm done, start flushing out any pending data that's left over".  But it never frees any underlying O/S resources or handles.

2) close() terminates the connection and frees O/S handles.  On windows, the function is called closesocket() and first initiates a shutdown (according to the definition above), if one has not been initiated already.  This behavior is not guaranteed as far as I know (someone correct me if I'm wrong) and probably does not happen on O/Ses other than Windows.  Even the windows documentation recommends not relying on it.   *IF* a graceful shutdown has been initiated *AND* the SO_LINGER option is set, then close() blocks until either a) the linger timeout has expired, or b) all pending data has been sent, whichever comes first.

Therefore, I believe the correct sequence is to first set the SO_LINGER option, then call shutdown, then call close.

Have you tried that?

Nick Aschberger

unread,
Jul 6, 2009, 11:47:03 PM7/6/09
to boost...@lists.boost.org
Hi All,

I know it's been a long time since I visited this thread - thanks Zach and Igor for your input here.

For all interested folks, it turns out that neither shutdown() or close() will guarantee that the data is sent. The actual behaviour is implementation/OS specific.

I found a blog entry that discussed this here:
http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable

In the end I have rearranged the code so that the final write is acked by the receiving side - now the communication is reliable.

cheers

Nick



Zachary Turner wrote:
Reply all
Reply to author
Forward
0 new messages