Re: How to Implement Streamed HTTP Request
Re: How to Implement Streamed HTTP Request
- Subject: Re: How to Implement Streamed HTTP Request
- From: Daniel Jalkut <email@hidden>
- Date: Thu, 27 Apr 2006 08:45:39 -0400
Hi Tommy - sorry for the delay in replying - I was out of town for a
few days.
I think you're getting confused by the use of the word "pair" in
different contexts. I'm also confused by this, so hopefully somebody
will correct us if what I'm about to tell you is wrong.
When you create a single socket, you're creating just one half of a
communication pair (say, the client half). From that single socket,
you can create a "pair" of streams: one for reading and one for
writing. The fact that there is a pair of streams doesn't change the
fact the socket itself is unconnected to anything else.
Using socketpair, you create a pair of sockets suitable for
communicating between say, a client and a server. The two sockets
represent two ends of a communications channel. Picture a long pipe
with your application code on one end, and CFNetwork on the other
end. You've created a socket pair so you can stick one socket on your
end and one on CFNetwork's end.
Now, you have to create streams for each of the sockets. In this
case, the server socket only needs a "read stream" so it can read
data out of the pipe, and the client socket only needs a write
stream, so it can write data to the pipe. The only purpose for these
streams is to push data out to the server as it's ready for it.
Here is an example from my working code. Again, if there are flaws in
it hopefully somebody more knowledgeable about this can help us out.
After I create "clientWriteStream" and "serverReadStream", I provide
the serverReadStream to the CFNetwork streamed upload API.
// To get a "callback based" read stream for our assets, we need to
create a
// local socket pair and give CFNetwork one of the socket streams
if (socketpair(AF_UNIX, SOCK_STREAM, 0, mySockets) != -1)
{
// Create CFStreams for the raw sockets
CFStreamCreatePairWithSocket(NULL, mySockets[0], serverReadStream,
NULL);
CFStreamCreatePairWithSocket(NULL, mySockets[1], NULL,
clientWriteStream);
if (*serverReadStream != NULL)
{
CFReadStreamSetProperty(*serverReadStream,
kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
}
if (*clientWriteStream != NULL)
{
CFWriteStreamSetProperty(*clientWriteStream,
kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
}
// Set the client
CFStreamClientContext myClientContext = {0, this, NULL, NULL, NULL};
if (CFWriteStreamSetClient(*clientWriteStream,
kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes |
kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
(CFWriteStreamClientCallBack) myCallbackPtr, &myClientContext) == false)
{
// Proprietary error logging mechanism
}
// Schedule on our run loop
CFWriteStreamScheduleWithRunLoop(*clientWriteStream,
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
// Open the write end so we can write to it when the server is
ready...
(void) CFWriteStreamOpen(*clientWriteStream);
// Open the read stream so CFNetwork can just read from the
stream to provide data to server
(void) CFReadStreamOpen(*serverReadStream);
success = true;
}
Hope this helps,
Daniel
On Apr 20, 2006, at 4:51 PM, Tommy Tian wrote:
Hi,Daniel
Thanks for reply, I also try this way before my first post. I use
CFStreamCreatePairWithSocket. but not success.
socket1 = socket(AF_UNIX, SOCK_STREAM, 0);
CFStreamCreatePairWithSocket(kCFAllocatorDefault, socket1,
&reqBodyStream, &reqBodyWriteStream);
CFWriteStreamSetClient(reqBodyWriteStream, kNetworkEvents,
reqBodyReadStreamClientCallBack, &ctxt);
CFWriteStreamScheduleWithRunLoop(reqBodyWriteStream,
CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
Boolean bOpen = CFWriteStreamOpen(reqBodyWriteStream);
there is no kCFSteamEventCanAcceptBytes call back, I don't know why.
I have two questions:
1. why you use socketpair to create a pair of sockets.
2. how can you create CFReadStream or CFWriteStream from the native
socket that created by socketpair.
On 4/20/06, Daniel Jalkut <email@hidden> wrote:
Hi Tommy - I accomplished something like what you're describing,
though it wasn't trivial.
I ended up using socketpair to create a pair of sockets that I could
then create a read and write stream for. Then I pass the read stream
to CFNetwork as the "requestBody" ref for the API below. The socket
write stream ref is used by my "send data" callback, which gets
triggered whenever the "can accept bytes" message comes in to the
client.
I implemented this a couple years ago in a shipping product and it
has been reliable. But there were some issues raised here about the
possible unreliability of socketpair based CFStreams. Maybe somebody
can update us on whether there is still cause for concern.
Daniel
On Apr 17, 2006, at 6:06 PM, Tommy Tian wrote:
Hi,All
I want use CFNetwork to implement streamed http post request.For
example send 1024 bytes to HTTPS server every 1 second.
I try use
extern CFReadStreamRef
CFReadStreamCreateForStreamedHTTPRequest(
CFAllocatorRef alloc,
CFHTTPMessageRef requestHeaders,
CFReadStreamRef requestBody)
This function seems fit for data of requestBody is ready for send
before call this function. (like requestBody from a file, or
memory),
can't be add any data to requestBody after it been called.
how can I send 100 memory bufferes to http server use one streamed
http request?of course can NOT merge 100 memory bufferes to one big
buffer and send it.
Thanks
-Tommy
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
sweater.com
This email sent to email@hidden
_______________________________________________
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