Re: Problem closing CFWriteStream [moved from darwin-dev, as it seems more appropriate here]
Re: Problem closing CFWriteStream [moved from darwin-dev, as it seems more appropriate here]
- Subject: Re: Problem closing CFWriteStream [moved from darwin-dev, as it seems more appropriate here]
- From: Eli Bach <email@hidden>
- Date: Fri, 20 Jun 2008 20:07:12 -0700
On Jun 20, 2008, at 7:18 PM, Jim Matthews wrote:
At 2:23 AM -0700 6/20/08, Eli Bach wrote:
How can I do an orderly vs a disorderly TCP disconnect using
CFWriteStream in my daemon?
I hope that someone from Apple responds, because I've wondered what
they recommend. What I've been doing, when I want to gracefully
close a connection, is:
- Finish writing any buffered data
- wait for the kCFStreamEventCanAcceptBytes callback
- call CFWriteStreamClose
- call shutdown(sock, SHUT_WR) on the native socket
- after the the paired CFReadStream closes, call close() on the
native socket
[I don't set kCFStreamPropertyShouldCloseNativeSocket]
The second thing is whether calling CFWriteStreamClose() forces the
write buffer to be flushed [at least, so any data buffered within
CF is pushed to the kernel]. Even if I get the native socket, then
call shutdown() on it, how can I be sure that the CFWriteStream
isn't still holding some buffered data?
If you get a kCFStreamEventCanAcceptBytes I believe that CFNetwork
has passed all the data to be written to the kernel, and it should
be safe to call CFWriteStreamClose and shutdown().
Yeah, this probably works, but the documentation doesn't explicitly
say that it has sent all data to the kernel (even after you call
CFWriteStreamClose()). I've filed a bug report about this, but I am
surprised that there have only been a couple of mentions of these
issues [handling an orderly close like this, or even a disorderly
close]. The stream networking API is from 10.2 or 10.3, so the API
should handle stuff like this.
Third, if an error happens, and I want to tear down the connection
in a 'disorderly' fashion [ie, not waiting for the send buffer to
be flushed to the client, which could potentially take minutes for
TCP to timeout], how do I do this?
Immediately call CFReadStreamClose and CFWriteStreamClose, and close
the native socket (if you haven't set
kCFStreamPropertyShouldCloseNativeSocket).
But I would expect this to possibly take several minutes before really
'closing' the connection, as there is no way to tell the stream the
difference between properly closing or not. Potentially, either
CFRead/WriteClose or the CFRelease could block the current thread
until TCP eventually gives up on the connection. Again, there is no
documentation on what happens, so really, anything can.
The more I think about this, this really seems like an API that's only
80% complete, that it looks like it could work well for doing
networking, but now that I've the core of it working [making the
connection, transferring data back and forth], and am now working on
error and stream closing, it looks like I have to ditch CFStream
altogether, as basic networking issues are not implemented and/or not
documented. And from every single WWDC I've been to [and I've gone to
10 of them], everyone at Apple says not to depend on undocumented
behaviour.
I'll look at the CFSocket stuff, but if that's at all like CFStream,
it might just be more deterministic to just fall back to the basic
unix API's, as it seems they figured out how to handle stuff like this
10 years or more ago.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden