Getting started with iOS development from samples (5)-HTTP-based Network Programming

Source: Internet
Author: User

In the previous article, we talked about how to transmit data over a Socket network. In fact, for Internet resources, we are more developed based on HTTP. simpleurlconnections shows how to transmit data over HTTP, this section mainly describes how the client requests and transmits data to the HTTP server. The implementation of the HTTP server is not within the scope of this example, but is actually a common HTTP server.

In this example, we can learn three points:

  • Download files based on get
  • Upload files based on put
  • Upload files based on post

Download files based on get

First open connection through URL:

    request = [NSURLRequest requestWithURL:url];    assert(request != nil);        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];    assert(self.connection != nil);

Then nsurlconnectiondelegate is implemented to process data transmission. The method for downloading an image to a local file is as follows:

- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data    // A delegate method called by the NSURLConnection as data arrives.  We just     // write the data to the file.{    #pragma unused(theConnection)    NSInteger       dataLength;    const uint8_t * dataBytes;    NSInteger       bytesWritten;    NSInteger       bytesWrittenSoFar;    assert(theConnection == self.connection);        dataLength = [data length];    dataBytes  = [data bytes];    bytesWrittenSoFar = 0;    do {        bytesWritten = [self.fileStream write:&dataBytes[bytesWrittenSoFar] maxLength:dataLength - bytesWrittenSoFar];        assert(bytesWritten != 0);        if (bytesWritten == -1) {            [self stopReceiveWithStatus:@"File write error"];            break;        } else {            bytesWrittenSoFar += bytesWritten;        }    } while (bytesWrittenSoFar != dataLength);}

Upload files based on put

Put is similar to get, except that file upload is completed by setting the HTTP header:

self.fileStream = [NSInputStream inputStreamWithFileAtPath:filePath];assert(self.fileStream != nil);// Open a connection for the URL, configured to PUT the file.request = [NSMutableURLRequest requestWithURL:url];assert(request != nil);[request setHTTPMethod:@"PUT"];[request setHTTPBodyStream:self.fileStream];if ( [filePath.pathExtension isEqual:@"png"] ) {    [request setValue:@"image/png" forHTTPHeaderField:@"Content-Type"];} else if ( [filePath.pathExtension isEqual:@"jpg"] ) {    [request setValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];} else if ( [filePath.pathExtension isEqual:@"gif"] ) {    [request setValue:@"image/gif" forHTTPHeaderField:@"Content-Type"];} else {    assert(NO);}contentLength = (NSNumber *) [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:NULL] objectForKey:NSFileSize];assert( [contentLength isKindOfClass:[NSNumber class]] );[request setValue:[contentLength description] forHTTPHeaderField:@"Content-Length"];self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

The most important thing is to set three header attributes: method, body, and contentlength.
[Request sethttpmethod: @ "put"];
[Request sethttpbodystream: Self. filestream];
[Request setvalue: [contentlength description] forhttpheaderfield: @ "Content-Length"];

Upload files based on post

The biggest difference between post-based file upload and put is that in addition to the data streams placed into the file itself in the HTTP body, structural descriptions must be placed before and after the file data stream, such as before:

bodyPrefixStr = [NSString stringWithFormat:            @            // empty preamble            "\r\n"            "--%@\r\n"            "Content-Disposition: form-data; name=\"fileContents\"; filename=\"%@\"\r\n"            "Content-Type: %@\r\n"            "\r\n"

After:

bodySuffixStr = [NSString stringWithFormat:            @            "\r\n"            "--%@\r\n"            "Content-Disposition: form-data; name=\"uploadButton\"\r\n"            "\r\n"            "Upload File\r\n"            "--%@--\r\n"             "\r\n"            //empty epilogue            ,            boundaryStr,             boundaryStr        ];

Therefore, we need to add the data to the file stream. In this example, we use the producer and consumer mode to splice the two pieces of information into the file stream:

[NSStream createBoundInputStream:&consStream outputStream:&prodStream bufferSize:32768];assert(consStream != nil);assert(prodStream != nil);self.consumerStream = consStream;self.producerStream = prodStream;self.producerStream.delegate = self;[self.producerStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];[self.producerStream open];// Set up our state to send the body prefix first.self.buffer      = [self.bodyPrefixData bytes];self.bufferLimit = [self.bodyPrefixData length];// Open a connection for the URL, configured to POST the file.request = [NSMutableURLRequest requestWithURL:url];assert(request != nil);[request setHTTPMethod:@"POST"];[request setHTTPBodyStream:self.consumerStream];[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=\"%@\"", boundaryStr] forHTTPHeaderField:@"Content-Type"];[request setValue:[NSString stringWithFormat:@"%llu", bodyLength] forHTTPHeaderField:@"Content-Length"];self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

Then process data stream splicing in handleevent:

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode    // An NSStream delegate callback that's called when events happen on our     // network stream.{    #pragma unused(aStream)    assert(aStream == self.producerStream);    switch (eventCode) {        case NSStreamEventOpenCompleted: {            // NSLog(@"producer stream opened");        } break;        case NSStreamEventHasBytesAvailable: {            assert(NO);     // should never happen for the output stream        } break;        case NSStreamEventHasSpaceAvailable: {            // Check to see if we've run off the end of our buffer.  If we have,             // work out the next buffer of data to send.                        if (self.bufferOffset == self.bufferLimit) {                // See if we're transitioning from the prefix to the file data.                // If so, allocate a file buffer.                                if (self.bodyPrefixData != nil) {                    self.bodyPrefixData = nil;                    assert(self.bufferOnHeap == NULL);                    self.bufferOnHeap = malloc(kPostBufferSize);                    assert(self.bufferOnHeap != NULL);                    self.buffer = self.bufferOnHeap;                                        self.bufferOffset = 0;                    self.bufferLimit  = 0;                }                                // If we still have file data to send, read the next chunk.                                 if (self.fileStream != nil) {                    NSInteger   bytesRead;                                        bytesRead = [self.fileStream read:self.bufferOnHeap maxLength:kPostBufferSize];                                        if (bytesRead == -1) {                        [self stopSendWithStatus:@"File read error"];                    } else if (bytesRead != 0) {                        self.bufferOffset = 0;                        self.bufferLimit  = bytesRead;                    } else {                        // If we hit the end of the file, transition to sending the                         // suffix.                        [self.fileStream close];                        self.fileStream = nil;                                                assert(self.bufferOnHeap != NULL);                        free(self.bufferOnHeap);                        self.bufferOnHeap = NULL;                        self.buffer       = [self.bodySuffixData bytes];                        self.bufferOffset = 0;                        self.bufferLimit  = [self.bodySuffixData length];                    }                }                                if ( (self.bufferOffset == self.bufferLimit) && (self.producerStream != nil) ) {                    self.producerStream.delegate = nil;                    [self.producerStream close];                }            }                        // Send the next chunk of data in our buffer.                        if (self.bufferOffset != self.bufferLimit) {                NSInteger   bytesWritten;                bytesWritten = [self.producerStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];                if (bytesWritten <= 0) {                    [self stopSendWithStatus:@"Network write error"];                } else {                    self.bufferOffset += bytesWritten;                }            }        } break;        case NSStreamEventErrorOccurred: {            NSLog(@"producer stream error %@", [aStream streamError]);            [self stopSendWithStatus:@"Stream open error"];        } break;        case NSStreamEventEndEncountered: {            assert(NO);     // should never happen for the output stream        } break;        default: {            assert(NO);        } break;    }}

Post-based data transmission seems complicated. In fact, the principle is still very simple. The focus is on data stream splicing.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.