[Cocoa] cfnetwork for iOS Network Programming

Source: Internet
Author: User

[Cocoa] cfnetwork for iOS Network Programming

Luo chaohui (http://www.cnblogs.com/kesalin)

This article follows the "signature-non-commercial use-consistency" creation public agreement I. Introduction to cfnetwork First, let's review it. In the previous article [Exploring cocoa] socket for iOS network programming, we mentioned that the Layer Model of IOS network programming is divided into three layers:
    • Cocoa layer: nsurl, bonjour, game kit, WebKit
    • Core Foundation layer:C-basedCfnetwork and cfnetservices
    • OS layer: C-based BSD socket
In the previous article, we talked about the underlying socket. This article will introduce the cfnetwork in the core foundation. Cfnetwork only implements lightweight encapsulation of BSD socket, but there is a significant benefit in using cfnetwork in iOS, that is, cfnetwork and system-level settings (such as antenna settings) and run-loop. Each thread has its own run-loop, so we can add the event source in the cfnetwork to the run-loop, so that we can process network events in the run-loop of the thread. BTW, the well-known asihttprequest library is encapsulated based on cfnetwork. ExampleCodeIn this case, check the source code: Https://github.com/kesalin/iOSSnippet/tree/master/KSNetworkDemo Ii. cfnetwork API Introduction The cfnetwork interface is C-based. The following interface is used to create a pair of socket streams for reading and writing:
 
Void Cfstreamcreatepairwithsockettohost(Cfallocatorref alloc, cfstringref host, uint32 port, cfreadstreamref * readstream, cfwritestreamref * writestream );

This function uses host and port. cfnetwork converts the host to an IP address and the network byte sequence. If we only need one socket stream, we can set another to null. There are two other interfaces for creating socket sream with "overload": cfstreamcreatepairwithsocket and cfstreamcreatepairwithpeersocketsignature. I will not describe them here.

Note: These socket streams must explicitly call their open functions like native sockets before they are used:

Boolean cfreadstreamopen (cfreadstreamref stream); Boolean cfwritestreamopen (cfwritestreamref stream );

However, unlike socket, these two interfaces are asynchronous. After successful open, if the caller sets the flag for obtaining the kcfstreameventopencompleted event, the caller calls the callback function.

The callback function and its parameter settings are implemented through the following interface:

 
BooleanCfreadstreamsetclient(Cfreadstreamref stream, cfoptionflags streamevents, cfreadstreamclientcallback clientcb, cfstreamclientcontext *Clientcontext); BooleanCfwritestreamsetclient(Cfwritestreamref stream, cfoptionflags streamevents, cfwritestreamclientcallback clientcb, cfstreamclientcontext* Clientcontext );

This function is used to set callback functions and related parameters. The streamevents flag is used to set the events we are interested in. clientcb is a callback function. When the event flag corresponds to an event, this callback function is called; clientcontext is used to pass parameters to the callback function.

After setting the callback function, we can schedule the socket stream to run-loop as the event source, so that the run-loop can distribute network events of the socket stream.

 
VoidCfreadstreamschedulewithrunloop(Cfreadstreamref stream, cfrunloopref runloop, cfstringref runloopmode );Void Cfwritestreamschedulewithrunloop(Cfwritestreamref stream, cfrunloopref runloop, cfstringref runloopmode );

Note: When we no longer care about the network events of the socket stream, remember to call the following interface to remove the socket stream from the Run-loop event source.

 
VoidCfreadstreamunschedulefromrunloop(Cfreadstreamref stream, cfrunloopref runloop, cfstringref runloopmode );Void Cfwritestreamunschedulefromrunloop(Cfwritestreamref stream, cfrunloopref runloop, cfstringref runloopmode );

After we schedule the network events of socket stream to run-loop, we can read data from various events in the callback function, such as kcfstreameventhasbytesavailable:

 
BooleanCfreadstreamhasbytesavailable(Cfreadstreamref stream); cfindexCfreadstreamread(Cfreadstreamref stream, uint8* Buffer, cfindex bufferlength );

Or kcfstreameventcanacceptbytes writes data:

 
BooleanCfwritestreamcanacceptbytes(Cfwritestreamref stream); cfindexCfwritestreamwrite(Cfwritestreamref stream,ConstUint8 * buffer, cfindex bufferlength );

Finally, we call the close method to close the socket stream:

 
VoidCfreadstreamclose (cfreadstreamref stream );VoidCfwritestreamclose (cfwritestreamref stream );

 

3. Client sample code

Similar to the socket demo, here I only demonstrate client examples. Similarly, we also start network operations in a background thread:

 
Nsurl * url = [nsurl urlwithstring: [nsstring stringwithformat:@"% @: % @", Serverhost, SERVERPORT]; nsthread* Backgroundthread =[[Nsthread alloc] initwithtarget: Self selector: @ selector (loaddatafromserverwithurl :)Object: Url]; [backgroundthread start];

Create a socket stream in loaddatafromserverwithurl, set its callback function, add it to the run-loop event source, and start it:

-( Void ) Loaddatafromserverwithurl :( nsurl * ) URL {nsstring * Host = [Url host]; nsinteger Port = [[Url port] integervalue];  //  Keep a reference to self to use for controller callbacks  // Cfstreamclientcontext CTX = { 0 , (_ Bridge Void * ) (Self), null };  //  Get callbacks for stream data, stream end, and any errors // Cfoptionflags registeredevents = (kcfstreameventhasbytesavailable | kcfstreameventendencountered | Kcfstreameventerroroccurred );  //  Create a read-only socket  //  Cfreadstreamref readstream;Cfstreamcreatepairwithsockettohost(Kcfallocatordefault, (_ bridge cfstringref) host, port, & Readstream, null );  //  Schedule the stream on the run loop to enable callbacks  //     If ( Cfreadstreamsetclient (Readstream, registeredevents, Socketcallback ,& CTX )){Cfreadstreamschedulewithrunloop(Readstream, cfrunloopgetcurrent (), kcfrunloopcommonmodes );}  Else  {[Self networkfailedwitherrormessage:  @"  Failed to assign callback Method  "  ];  Return  ;}  // Open the stream for reading  //      If ( Cfreadstreamopen (Readstream) = No) {[self networkfailedwitherrormessage:  @"  Failed to open read stream  "  ];  Return  ;} Cferrorref Error = Cfreadstreamcopyerror(Readstream );  If (Error! =Null ){  If (Cferrorgetcode (error )! = 0  ) {Nsstring * Errorinfo = [nsstring stringwithformat: @"  Failed to connect stream; error '% @' (code % LD)  " , (_ Bridge nsstring * ) Cferrorgetdomain (error), cferrorgetcode (error)]; [self networkfailedwitherrormessage: errorinfo];} cfrelease (error );  Return  ;} Nslog (  @" Successfully connected to % @  "  , URL );  //  Start processing  //  Cfrunlooprun();} 

Refer to the preceding interface description to understand the above Code. The only interface not mentioned above is cfreadstreamcopyerror, which is used to obtain the current error message. If there is no error, null is returned.

 
Cferrorref cfreadstreamcopyerror (cfreadstreamref stream); cferrorref cfwritestreamcopyerror (cfwritestreamref stream );

In addition, we can call the following interface to obtain the current status of socket stream:

 
Cfstreamstatus cfreadstreamgetstatus (cfreadstreamref stream); cfstreamstatus cfwritestreamgetstatus (cfwritestreamref stream );

In the code above, we set the callback function socketcallback to be called when data can be read, when the stream reaches the end, and when an error occurs:

 Void Socketcallback (cfreadstreamref stream, cfstreameventtype Event , Void * Myptr) {kscfnetworkviewcontroller * Controller = (_ bridge kscfnetworkviewcontroller * ) Myptr;  Switch ( Event  ){  Case  Kcfstreameventhasbytesavailable:{  // Read bytes until there are no more  //              While  (Cfreadstreamhasbytesavailable(Stream) {uint8 buffer [kbuffersize];  Int Numbytesread = Cfreadstreamread(Stream, buffer, kbuffersize); [controller didreceivedata: [nsdata datawithbytes: Buffer length: numbytesread];}  Break  ;}  Case Kcfstreameventerroroccurred: {cferrorref Error = Cfreadstreamcopyerror(Stream );  If (Error! = Null ){  If (Cferrorgetcode (error )! = 0  ) {Nsstring * Errorinfo = [nsstring stringwithformat: @"  Failed while reading stream; error '% @' (code % LD)  " , (_ Bridge nsstring *) Cferrorgetdomain (error), cferrorgetcode (error)]; [controller networkfailedwitherrormessage: errorinfo];} cfrelease (error );}  Break  ;}  Case  Kcfstreameventendencountered:  //  Finnish Receiveing data  //  [Controller didfinishreceivingdata];  // Clean up  //  Cfreadstreamclose(Stream );Cfreadstreamunschedulefromrunloop(Stream, cfrunloopgetcurrent (), kcfrunloopcommonmodes );Cfrunloopstop(Cfrunloopgetcurrent ());  Break  ;  Default  :  Break  ;}} 

The above code is also easy to understand. When there is data that can be read, read it, and then update the UI. When the stream reaches the end, close the stream and perform cleanup. When an error is sent, report error information.

 

Iv. Expansion

Although the Code above only demonstrates how to use cfreadstream of cfnetwork to read data and write data using cfwritestream, the workflow is the same. I will not introduce it here.

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.