This article reprinted to http://blog.csdn.net/kesalin/article/details/8798039Category:IOS Development2013-04-13 20:51 9361 people read reviews Collection report Iosnetwork
Directory (?) [+]
[In layman's Cocoa]ios network programming socket
Roche (Http://blog.csdn.net/kesalin) CC license, reprint please specify the source more Cocoa development articles, please visit "Cocoa" csdn column: http://blog.csdn.net/column/ Details/cocoa.html
One, iOS network programming hierarchy model
In the previous article, "Simple Cocoa Bonjour Network Programming" I introduced how to do Bonjour programming in the Mac system, in that article also introduced in the COCOA network programming hierarchy is divided into three layers, although the demo is a MAC system example, The same is true for iOS systems. The iOS network programming hierarchy is also divided into three tiers:
- Cocoa Layer: Nsurl,bonjour,game kit,webkit
- Core Foundation layer: C-based Cfnetwork and Cfnetservices
- OS layer: BSD socket based on C
The cocoa layer is the topmost objective-c-based API, such as URL access, Nsstream,bonjour,gamekit, etc., which is commonly used in most cases. The COCOA layer is implemented based on the Core Foundation.
Core Foundation layer: Because the direct use of the socket requires more programming work, Apple's socket on the OS layer is simply encapsulated to simplify programming tasks. This layer provides cfnetwork and cfnetservices, where Cfnetwork is also based on Cfstream and Cfsocket.
OS layer: The lowest-level BSD socket provides maximum control over network programming, but it also has the most programming effort. Therefore, Apple recommends that we use the Core Foundation and the API of the above layer to program.
This article will show you how to program with the most basic socket in IOS, which is not very different from socket programming using C + + in the window System.
This article source: Https://github.com/kesalin/iOSSnippet/tree/master/KSNetworkDemo
The results are as follows:
Second, BSD socket API Introduction
The BSD socket API and the Winsock API interface are roughly the same, and the more commonly used APIs are listed below:
API interface |
Explain |
Socket (int addressfamily, int type, int protocol) Close (int socketfiledescriptor) |
The socket creates and initializes the socket, returns the file descriptor of the socket, or 1 if the descriptor indicates that the creation failed. Usually the parameter addressfamily is IPv4 (af_inet) or IPV6 (AF_INET6). Type represents the types of sockets, usually stream stream (SOCK_STREAM) or data message datagram (SOCK_DGRAM). The protocol parameter is typically set to 0 so that the system automatically chooses our appropriate protocol, which is the TCP Protocol (IPPROTO_TCP) for the stream socket, and the UDP Protocol (IPPROTO_UDP) for datagram. Close closes the socket. |
int bind(int socketfiledescriptor,Sockaddr *addresstobind, int addressstructlength) |
Binds the socket to a specific host address and port number, the successful binding returns 0, and the failure returns-1. After a successful binding, depending on the protocol (TCP/UDP), we can do different things to the socket: UDP: Because UDP is not connected, you can use UDP sockets to transmit data after binding. TCP: While TCP is required to establish an end-to-end connection, in order to establish a TCP connection the server must call listen (int socketfiledescriptor, int backlogsize) to set the server's buffer queue to receive client connection requests. Backlogsize represents the size of the client connection request buffer queue. When the listen setting is called, the server waits for a client request and then invokes the following accept to accept the client's connection request. |
int Accept(int socketfiledescriptor,sockaddr *clientaddress, intclientaddressstructlength) |
Accepts the client connection request and saves the client's network address information to clientaddress. When a client connection request is accepted by the server, the link between the client and the server is established and the two can communicate. |
int connect(int socketfiledescriptor,sockaddr *serveraddress, intserveraddresslength) |
The client sends a connection request to the server for a specific network address, the connection returns 0 successfully, and the failure returns-1. When the server is established, the client initiates a connection request to the server by invoking the interface. For UDP, the interface is optional, and if the interface is called, the default network address for that UDP socket is set. For TCP sockets This is where the legendary three-time handshake establishes the connection. Note: This interface call blocks the current thread until the server returns. |
gethostbyname (Char *hostname) |
Use DNS to find the IP address that corresponds to a specific host name. Returns NULL if the corresponding IP address is not found. |
int send(int socketfiledescriptor, char*buffer, int bufferlength, int flags) |
Sends the data through the socket, sends the successful return the number of bytes sent successfully, otherwise returns-1. Once the connection is established, the data can be sent or received via the Send/receive interface. Note A UDP socket that calls connect to set the default network address can also call the interface to receive data. |
int receive(int socketfiledescriptor,char *buffer, int bufferlength, int flags) |
Reads the data from the socket, the read successfully returns the number of bytes successfully read, otherwise returns-1. Once the connection is established, the data can be sent or received via the Send/receive interface. Note A UDP socket that calls connect to set the default network address can also call this interface to send data. |
int sendto(int socketfiledescriptor,char *buffer, int bufferlength, intflags, sockaddr *destinationaddress, Intdestinationaddresslength) |
Send data to a specific network address via a UDP socket, sending a successful return of the number of bytes successfully sent, otherwise return-1. Because UDP can send data to multiple network addresses, you can specify a specific network address to send data to. |
int recvfrom(int socketfiledescriptor,char *buffer, int bufferlength, intFlags, sockaddr *fromaddress, int *fromaddresslength) |
Reads the data from the UDP socket and saves the sender's network address information, the read successfully returns the number of bytes successfully read, otherwise returns-1. Because UDP can receive data from multiple network addresses, additional parameters need to be provided to hold the sender identity of the data. |
Third, server workflow
With the above socket API explained, the following summarizes the server workflow.
- The server calls the socket (...) to create the socket;
- The server calls listen (...) to set the buffer;
- Server via Accept (...) Accept client requests to establish a connection;
- After the server has established a connection with the client, it can pass the Send (...) /receive (...) Sending or receiving data from the client;
- The server calls close to close the socket;
Since iOS devices are typically client-side, there is no code in this article to demonstrate how to set up an IOS server, but you can refer to the previous article: "Bonjour network programming in cocoa" to see how to build a desktop server under a MAC system.
Four, client workflow
Because the IOS device is typically a client, the following shows how to write client code. Let's summarize the client workflow.
- The client calls the socket (...) to create the socket;
- The client calls connect (...) to initiate a connection request to the server to establish the connection;
- After the client has established a connection to the server, it can pass the Send (...) /receive (...) Sending or receiving data from the client;
- The client calls close to close the socket;
Five, client code example
The following code implements the workflow for the above client:
-(void) Loaddatafromserverwithurl: (Nsurl *) url{NSString * host = [URL host]; NSNumber * port = [url port]; Create socket//INT socketfiledescriptor =Socket(Af_inet, Sock_stream, 0); if ( -1 = = Socketfiledescriptor) {NSLog (@ "Failed to create socket."); Return }//Get IP address from host//struct hostent * remotehostent =gethostbyname([host utf8string]); if (NULL = = remotehostent) {close (socketfiledescriptor); [Self networkfailedwitherrormessage:@ "unable to resolve the hostname of the warehouse server."]; Return } struct in_addr * remoteinaddr = (struct in_addr *) remotehostent->h_addr_list[0]; Set the socket parameters//struct sockaddr_in socketparameters; socketparameters.sin_family = af_inet; SOCKETPARAMETERS.SIN_ADDR = *remoteinaddr; Socketparameters.sin_port = htons ([port Intvalue]); Connect the socket//INT ret =Connect(Socketfiledescriptor, (struct sockaddr *) &socketparameters, sizeof (socketparameters)); if ( -1 = = ret) {close (socketfiledescriptor); NSString * errorinfo = [NSString stringwithformat:@ ">> Failed to connect to%@:%@", host, Port]; [Self networkfailedwitherrormessage:errorinfo]; Return } NSLog (@ ">> successfully connected to%@:%@", host, Port); Nsmutabledata * data = [[Nsmutabledata alloc] init]; BOOL waitingfordata = YES; Continually receive data until we reach the end of the data//int maxCount = 5; Just for Test. int i = 0; while (Waitingfordata && i < maxCount) {const char * buffer[1024]; int length = sizeof (buffer); Read A buffer ' s amount of data from the socket; The number of bytes read is returned//int result =recv(Socketfiledescriptor, &buffer, length, 0); if (Result > 0) {[Data appendbytes:buffer length:result]; } else {//if we didn ' t get any data, stop the receive loop//Waitingfordata = N O } ++i; }//Close the socket//Close(Socketfiledescriptor); [Self networksucceedwithdata:data];}
As I said earlier, interfaces such as Connect/recv/send are blocked, so we need to put these operations in a non-UI thread. As shown below:
Nsthread * Backgroundthread = [[Nsthread alloc] initwithtarget:self selector: @selector (loaddatafromserverwithurl :) Object:url]; [Backgroundthread start];
Again, we need to update the UI in order to get the data or the network exception that caused the task to fail, and that's going to go back to the UI thread to do the same thing. As shown below:
-(void) Networkfailedwitherrormessage: (NSString *) message{ //Update UI // [[Nsoperationqueue Mainqueue ] addoperationwithblock:^{ NSLog (@ "%@", message); Self.receiveTextView.text = message; self.connectButton.enabled = YES; [Self.networkactivityview stopanimating]; }];} -(void) Networksucceedwithdata: (NSData *) data{ //Update UI // [[Nsoperationqueue Mainqueue] addoperationwithblock:^{ NSString * resultsstring = [[NSString alloc] initwithdata:data encoding: Nsutf8stringencoding]; NSLog (@ ">> Received string: '%@ '", resultsstring); Self.receiveTextView.text = resultsstring; self.connectButton.enabled = YES; [Self.networkactivityview stopanimating]; }];}
[In layman's Cocoa]ios network programming socket