Getting started with iOS development from samples (4)-socket-Based Network Programming

Source: Internet
Author: User

Simplenetworkstreams demonstrates how to program on the Socket network to implement a typical scenario of network data transmission in the LAN. One is that the client sends a local image file to the server, the other is that the client downloads images from the server to a local file. General process:

  • Server enables socket listening

Here, IOS generally follows three steps:

Step 1: Create a system-level socket and bind the port

    port = 0;        fd = socket(AF_INET, SOCK_STREAM, 0);    success = (fd != -1);        if (success) {        memset(&addr, 0, sizeof(addr));        addr.sin_len    = sizeof(addr);        addr.sin_family = AF_INET;        addr.sin_port   = 0;        addr.sin_addr.s_addr = INADDR_ANY;        err = bind(fd, (const struct sockaddr *) &addr, sizeof(addr));        success = (err == 0);    }    if (success) {        err = listen(fd, 5);        success = (err == 0);    }    if (success) {        socklen_t   addrLen;        addrLen = sizeof(addr);        err = getsockname(fd, (struct sockaddr *) &addr, &addrLen);        success = (err == 0);                if (success) {            assert(addrLen == sizeof(addr));            port = ntohs(addr.sin_port);        }    }

Port = 0 is used to allow the system to randomly find an idle port. Others are direct calls to system functions based on the C style.

Step 2: Use IOS socket (cfsocket) to package system socket

CFSocketContext context = { 0, (__bridge void *) self, NULL, NULL, NULL };assert(self->_listeningSocket == NULL);self->_listeningSocket = CFSocketCreateWithNative(    NULL,     fd,     kCFSocketAcceptCallBack,     AcceptCallback,     &context);success = (self->_listeningSocket != NULL);if (success) {    CFRunLoopSourceRef  rls;        fd = -1;        // listeningSocket is now responsible for closing fd    rls = CFSocketCreateRunLoopSource(NULL, self.listeningSocket, 0);    assert(rls != NULL);        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);        CFRelease(rls);}

The purpose of packaging the socket here is to facilitate subsequent event listening and processing, and transfer the development based on the original ecological socket to the IOS layer. Here, the accept event listening function is acceptcallback, and run it in a separate thread.

Step 3: Use nsnetservice to publish a socket

if (success) {    self.netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_x-SNSUpload._tcp." name:@"Test" port:port];    success = (self.netService != nil);}if (success) {    self.netService.delegate = self;        [self.netService publishWithOptions:NSNetServiceNoAutoRename];        // continues in -netServiceDidPublish: or -netService:didNotPublish: ...}

The previously created socket is released based on nsnetservice to facilitate clienti connection and request.

  • The client initiates a socket connection request.

Here, the client releases netservice through the server and initiates a connection to the socket:

netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_x-SNSUpload._tcp." name:@"Test"];

  • Server listens for and processes data requests

The server will enable stream on the socket in the callback function of the accept event listening, and listen on various Io events on the stream:

CFStreamCreatePairWithSocket(NULL, fd, &readStream, NULL);assert(readStream != NULL);self.networkStream = (__bridge NSInputStream *) readStream;CFRelease(readStream);[self.networkStream setProperty:(id)kCFBooleanTrue forKey:(NSString *)kCFStreamPropertyShouldCloseNativeSocket];self.networkStream.delegate = self;[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];[self.networkStream open];

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode    // An NSStream delegate callback that's called when events happen on our     // network stream.{    assert(aStream == self.networkStream);    #pragma unused(aStream)    switch (eventCode) {        case NSStreamEventOpenCompleted: {            [self updateStatus:@"Opened connection"];        } break;        case NSStreamEventHasBytesAvailable: {            NSInteger       bytesRead;            uint8_t         buffer[32768];            [self updateStatus:@"Receiving"];            // Pull some data off the network.                        bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];            if (bytesRead == -1) {                [self stopReceiveWithStatus:@"Network read error"];            } else if (bytesRead == 0) {                [self stopReceiveWithStatus:nil];            } else {                NSInteger   bytesWritten;                NSInteger   bytesWrittenSoFar;                // Write to the file.                                bytesWrittenSoFar = 0;                do {                    bytesWritten = [self.fileStream write:&buffer[bytesWrittenSoFar] maxLength:bytesRead - bytesWrittenSoFar];                    assert(bytesWritten != 0);                    if (bytesWritten == -1) {                        [self stopReceiveWithStatus:@"File write error"];                        break;                    } else {                        bytesWrittenSoFar += bytesWritten;                    }                } while (bytesWrittenSoFar != bytesRead);            }        } break;        case NSStreamEventHasSpaceAvailable: {            assert(NO);     // should never happen for the output stream        } break;        case NSStreamEventErrorOccurred: {            [self stopReceiveWithStatus:@"Stream open error"];        } break;        case NSStreamEventEndEncountered: {            // ignore        } break;        default: {            assert(NO);        } break;    }}

The above code writes data to a local file when the server detects that data has been sent. In fact, the network inputstream is written to the outputstream of the file. Here, the handleevent method is the callback function of the IO event after self. networkstream. Delegate = self is set. In handleevent, different processing needs to be performed based on different event types.

  • Client sends and accepts data streams

The client's data processing is similar to that of the server through listening to network stream events:

self.networkStream = output;self.networkStream.delegate = self;[self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];[self.networkStream open];

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode    // An NSStream delegate callback that's called when events happen on our     // network stream.{    assert(aStream == self.networkStream);    #pragma unused(aStream)    switch (eventCode) {        case NSStreamEventOpenCompleted: {            [self updateStatus:@"Opened connection"];        } break;        case NSStreamEventHasBytesAvailable: {            assert(NO);     // should never happen for the output stream        } break;        case NSStreamEventHasSpaceAvailable: {            [self updateStatus:@"Sending"];                        // If we don't have any data buffered, go read the next chunk of data.                        if (self.bufferOffset == self.bufferLimit) {                NSInteger   bytesRead;                                bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize];                                if (bytesRead == -1) {                    [self stopSendWithStatus:@"File read error"];                } else if (bytesRead == 0) {                    [self stopSendWithStatus:nil];                } else {                    self.bufferOffset = 0;                    self.bufferLimit  = bytesRead;                }            }                        // If we're not out of data completely, send the next chunk.                        if (self.bufferOffset != self.bufferLimit) {                NSInteger   bytesWritten;                bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];                assert(bytesWritten != 0);                if (bytesWritten == -1) {                    [self stopSendWithStatus:@"Network write error"];                } else {                    self.bufferOffset += bytesWritten;                }            }        } break;        case NSStreamEventErrorOccurred: {            [self stopSendWithStatus:@"Stream open error"];        } break;        case NSStreamEventEndEncountered: {            // ignore        } break;        default: {            assert(NO);        } break;    }}

The process here is opposite to the server. It reads data from the inputstream of the file and writes it to the outputsteam of the network.

The above is the general Socket network programming mode in IOS.

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.