Re: TCP Socket keepalive
Haitao Zhang <[email protected]>
| Newsgroups | gmane.comp.ai.prolog.swi |
|---|---|
| Message-ID | <CAFUyvhoHJn7RXuwpVbvEa-r=Kg9qfk7pSw2=_PYZdurz7xJ9ww@mail.gmail.com> |
Ha! Thanks for explaining the difference between close/1 and close/2 with force(true). Now I see what my mistake is. I should close a broken stream with close/2 with force(true) instead. On Fri, Dec 13, 2013 at 12:23 AM, Jan Wielemaker <[email protected]> wrote: > On 12/13/2013 06:44 AM, Haitao Zhang wrote: > > Hi Jeff, > > > > Thanks for the explanation. What is interesting in my case is that the > > tcp connection was definitely established. I intend it to be a long > > session (it connects to a 127.0.0.x port to talk a local service), but > > it sometimes loses the connection due to inactivity (more on this > > later). At such times a write to the stream would raise an error, which > > is expected. What is surprising is that close(Stream) also raises an > > error. My guess is that the underlying stream has already been closed by > > the native socket library unbeknownst to Prolog (I am on Windows), so > > both actions raise the same WSAENOTSOCK error (I traced that far by > > grepping the "Socket operation on non-socket" message). I am okay with > > it although I would have expected close/1 to intercept the exception in > > this case, since there is a well defined semantics here (close(close()) > > == close() idempotent?). > > No. We are talking about streams. If you open a stream, write to it and > close and get no error, you want the guarantee that all data has been > transferred. So, close only succeeds if it successfully flushed the > remaining buffer (if relevant) and can cleanly close the socket. There > is close/2 with the option force(true) that closes the socket without > worrying about errors. I.e., it performs the same operations, but succeeds > no matter what happens. > > Otherwise, I think you are right and you need something that detects > connection errors > and reconnects for dealing with these scenarios ... > > > > Now back to the original issue of keeping the connection, it seems that > > TCP keepalive should really be used to detect failed connections and > > release resources. TCP connection should not expire unless explicitly > > released. What happened was: if my computer goes to sleep, after waking > > up the Prolog client can send one packet successfully, but fails on the > > second attempt. So it looks like some socket internal stuff fell out of > > sync. But the server is unaware of this so it is not a reset from the > > server side. Subsequently I can reconnect but open threads are piling up > > on the server side. So I implemented tcp keepalive on the server side to > > get rid of dead connections. Interestingly now the Prolog client side > > starts to fail sooner -- I assume after the connection being idle for > > two hours the server side starts sending keepalive packets to the client > > side and the client side somehow shuts down the socket in response. Now > > all of these could be completely internal to the winsock library so > > Prolog would have no control over it, but I really can't tell. > > > > It seems that most people recommend application level keep-alive if one > > wants to keep a connection around. > > > > > > > > On Wed, Dec 11, 2013 at 4:48 PM, Jeff Rosenwald <[email protected] > > <mailto:[email protected]>> wrote: > > > > Hi Haitao: > > > > Supposing that your client looks something like this: > > > > client_stream(IPAddress, In, Out) :- > > tcp_socket(S), > > tcp_connect(S, IPAddress, In, Out). > > > > If client_stream/3 succeeds then In and Out will be unified with the > > appropriate Prolog streams. If it succeeds, then safety requires > > that you eventually close both streams using > > "close(Stream, [force(true)])," and you must not release the socket > > via tcp_close_socket/1 since it is no longer valid. > > > > BUT, it is perfectly reasonable to expect that occasionally the > > above will throw an exception due the failure to connect. In that > > case you *must not* close the streams since they are unbound and you > > must release the socket using tcp_close_socket/1. If you don't then > > the socket is leaked. > > > > Your client_stream/3 needs to look something like: > > > > client_stream(IPAddress, In, Out) :- > > setup_call_catcher_cleanup(tcp_socket(Socket), > > tcp_connect(Socket, IPAddress, > > In, Out), > > exception(_), > > tcp_close_socket(Socket)). > > > > (Code not tested) > > > > Please see Section 6.2 of the clib docs to see how the socket should > > be managed at this critical time. > > > > Regards, > > Jeff R. > > > > -----Original Message----- > > From: Haitao Zhang <[email protected] <mailto:[email protected]>> > > To: Jan Wielemaker <[email protected] <mailto:[email protected]>> > > Cc: swi-prolog <[email protected] > > <mailto:[email protected]>> > > Sent: Wed, Dec 11, 2013 3:08 am > > Subject: Re: [SWIPL] TCP Socket keepalive > > > > Hi Jan, > > > > Thanks for the response. I will take a look at tcp_setopt/setsockopt. > > > > On a related note, after the send error (as the socket closed > unexpectedly) > > if I call close/1 on the stream, I get the same error. Now that is a > little > > confusing. Shouldn't close/1 just silently ignore the error? > > tcp_close_socket on the other hand seems to gracefully handle the > > situation. When I close down a channel, should I > > > > A) just call tcp_close_socket on the socket, and don't call close on > the > > stream? > > > > or > > > > B) do both, but wrap the close on the stream to trap the error > condition? > > It seems weird that one needs to wrap the close/1 since it should be > in the > > cleanup clause of an exception handler. > > > > Haitao > > > > > > On Tue, Dec 10, 2013 at 12:57 AM, Jan Wielemaker <[email protected]<mailto: > [email protected]>> wrote: > > > > > On 12/10/2013 08:26 AM, Haitao Zhang wrote: > > > > > >> I have a problem with the TCP socket, where SWI Prolog is client, > > >> disappearing after some time (presumably some inactivity timer > expired). I > > >> have set my server side to keepalive, but that does not seem to > help. > > >> > > >> The message I get from trying to use the socket again after a > long idle > > >> time: > > >> ERROR: format/3: I/O error in write on stream > <stream>(000000000834B260) > > >> (Socket operation on non-socket) > > >> > > >> Any idea on how keep the socket alive? > > >> > > > > > > There is tcp_setopt/2, which binds to setsockopt(). It doesn't > support > > > the SO_KEEPALIVE option yet. Should be easy enough to add. If > you use > > > a source version, see packages/clib. Try it and submit a patch > with > > > additional options you see fit. > > > > > > Hope this helps > > > > > > --- Jan > > > > > > > > > > > >> Thanks, > > >> Haitao > > >> -------------- next part -------------- > > >> HTML attachment scrubbed and removed > > >> _______________________________________________ > > >> SWI-Prolog mailing list > > >> [email protected] <mailto: > [email protected]> > > >> https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog > > >> > > >> > > > > > -------------- next part -------------- > > HTML attachment scrubbed and removed > > _______________________________________________ > > SWI-Prolog mailing list > > [email protected] <mailto: > [email protected]> > > https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog > > > > > -------------- next part -------------- HTML attachment scrubbed and removed