The socket is created as follows (error handling omitted):
socket = SockSocket('AF_INET', 'SOCK_STREAM', 0 )
CALL SockIoctl socket, 'FIONBIO', 1
rc = SockSetSockOpt( socket, 'SOL_SOCKET', 'SO_LINGER', '1 2')
address.!family = 'AF_INET'
address.!port = 2780
address.!addr = 'INADDR_ANY'
rc = SockBind( socket, 'address.!')
rc = SockListen( socket, 5 )
The daemon thread is then started, which basically runs a SockAccept() loop
until a quit event is posted, at which point it calls SockClose( socket )
and then signals the main program to exit.
This works fine about 80% of the time. Sometimes, however, I discover
once the program has exited that the socket is still open, stalled in
TIME_WAIT status. It usually stays that way for about 20 seconds or so,
during which time of course I can't restart the daemon successfully.
I've tried with SO_LINGER both enabled and disabled. It makes no apparent
difference.
How can I make sure this wretched socket gets closed when the program
does?
--
Alex Taylor
Fukushima, Japan
http://www.socis.ca/~ataylo00
Please take off hat when replying.
Do you do anything to unblock the receiving thread before exiting? Or
is the thread killed "harshly" when the main thread exits?
--
[Reverse the parts of the e-mail address to reply.]
> > The daemon thread is then started, which basically runs a SockAccept()
> > loop until a quit event is posted, at which point it calls SockClose(
> > socket ) and then signals the main program to exit.
> >
> > This works fine about 80% of the time. Sometimes, however, I discover
> > once the program has exited that the socket is still open, stalled in
> > TIME_WAIT status. It usually stays that way for about 20 seconds or so,
> > during which time of course I can't restart the daemon successfully.
>
> Do you do anything to unblock the receiving thread before exiting? Or
> is the thread killed "harshly" when the main thread exits?
As I say, on program exit, I post an event to the daemon thread which tells
it to break out of its loop. At that point, it calls SockClose, then posts
an event back to the main program tell it that it's safe to exit.
When the user goes to exit the program, I post this event to the daemon
thread:
IF listener.!thread > 0 THEN DO
rc = VRMethod('Application', 'PostQueue',,
listener.!thread, 0, 'finished = 1')
END
(I also post termination messages to any client socket threads that may be
active, but that part seems to be working as it should.)
The daemon thread's loop looks like this:
finished = 0
CALL VRInit
DO WHILE finished == 0
csock = SockAccept( socket )
IF csock > 0 THEN DO
CALL VRMethod 'Application', 'PostQueue', 0, 1,,
'CALL Event_Incoming', 'ClientSocket', csock
END
_VREEvent = VREvent('N')
INTERPRET _VREEvent
END
IF socket > 0 THEN DO
rc = SockClose( socket )
IF rc \= 0 THEN CALL SockPSock_ErrNo()
END
CALL VRMethod 'Application', 'PostQueue', 0, 1, 'CALL Quit'
CALL VRFini
At which point the "Quit" method in the main program simply destroys the
window and exits, as usual.
> The daemon thread is then started, which basically runs a SockAccept() loop
> until a quit event is posted, at which point it calls SockClose( socket )
> and then signals the main program to exit.
>
> This works fine about 80% of the time. Sometimes, however, I discover
> once the program has exited that the socket is still open, stalled in
> TIME_WAIT status. It usually stays that way for about 20 seconds or so,
> during which time of course I can't restart the daemon successfully.
>
> I've tried with SO_LINGER both enabled and disabled. It makes no apparent
> difference.
>
> How can I make sure this wretched socket gets closed when the program
> does?
It's all very annoying. I've never got to the bottom of it. Have you
tried putting in a SockShutDown() to see if that helps?
> > How can I make sure this wretched socket gets closed when the program
> > does?
>
> It's all very annoying. I've never got to the bottom of it.
Ah, so it's not just me? Not sure if that's a relief or a worry. :)
Does it happen only with RXSOCK, or with sockets in general?
> Have you tried putting in a SockShutDown() to see if that helps?
Well, now I have. And no, it doesn't help. :(
>> > How can I make sure this wretched socket gets closed when the program
>> > does?
>>
>> It's all very annoying. I've never got to the bottom of it.
>
> Ah, so it's not just me? Not sure if that's a relief or a worry. :)
>
> Does it happen only with RXSOCK, or with sockets in general?
In general I think.
>> Have you tried putting in a SockShutDown() to see if that helps?
>
> Well, now I have. And no, it doesn't help. :(
Oh well, worth a shot. I think you'll just have to learn to live with it.
>>> > How can I make sure this wretched socket gets closed when the program
>>> > does?
>>>
>>> It's all very annoying. I've never got to the bottom of it.
>>
>> Ah, so it's not just me? Not sure if that's a relief or a worry. :)
>>
>> Does it happen only with RXSOCK, or with sockets in general?
>
> In general I think.
>
>>> Have you tried putting in a SockShutDown() to see if that helps?
>>
>> Well, now I have. And no, it doesn't help. :(
>
> Oh well, worth a shot. I think you'll just have to learn to live with it.
Actually, having pursued this a bit more, I find that my server only
fails to bind with an "Address in use" error if it had connected clients
at the time I closed it, despite disconnecting them properly.
If it had no clients it restarted fine every time.
"netstat -s" never showed any lingering sockets either way.
Subsequent to this, I added a SO_REUSEADDR setsocketopt() to the socket
before binding and it now works properly all the time.
I can't remember why I didn't do this before...
This is on a machine with a 16 bit TCP/IP stack though. Perhaps I should
try it on a 32 bit stack as well.
Is there some chance that the main application can post its message to
terminate the thread, but not give up the rest of its timeslice and exit
before the thread gets the message? In C-land, I would have some kind
of DosWaitThread type of thing in there.
> > As I say, on program exit, I post an event to the daemon thread which
> > tells it to break out of its loop. At that point, it calls SockClose,
> > then posts an event back to the main program tell it that it's safe to
> > exit.
>
> Is there some chance that the main application can post its message to
> terminate the thread, but not give up the rest of its timeslice and exit
> before the thread gets the message? In C-land, I would have some kind
> of DosWaitThread type of thing in there.
I don't see how. If the daemon thread is active, then the main program
can only quit once it receives the 'done' message from the listener.
But I have no way of knowing what the VX-REXX runtime is doing internally,
of course...
> Actually, having pursued this a bit more, I find that my server only
> fails to bind with an "Address in use" error if it had connected clients
> at the time I closed it, despite disconnecting them properly.
> If it had no clients it restarted fine every time.
> "netstat -s" never showed any lingering sockets either way.
>
> Subsequent to this, I added a SO_REUSEADDR setsocketopt() to the socket
> before binding and it now works properly all the time.
> I can't remember why I didn't do this before...
>
> This is on a machine with a 16 bit TCP/IP stack though. Perhaps I should
> try it on a 32 bit stack as well.
Well, so far it seems to work here (crossing fingers). MPTS WR08708
(eCS 2.0rc4).
Thanks for the hint!