Communication between iOS apps-local socket, ios-local
I saw an article about five communication methods between apps, including URL Scheme, Keychain, UIPastedboard, UIDocumentInteractionController, and local communication using socket. The first four are useful and relatively simple, just a few lines of code. I have never used the last one before (forgive me for being a little white), so I tried to write it today. Here we will share the record with you.
Okay, let's not talk much about it. Start:
First of all, let's talk about its principle. It's actually very simple. An App performs TCP bind and listen on the local port, and another App performs connect on the local port, in this way, a normal TCP connection is established, and data can be transmitted if you want to transmit any data.Create a server first:
1. First, use the socket () function to create a socket
/** The socket returns an int value.-1 indicates the creation failure * The first parameter specifies the protocol family/domain, which usually includes AF_INET (IPV4) and AF_INET6 (IPV6) AF_LOCAL * The second parameter specifies a set of interface types: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc. * The third parameter specifies the corresponding transmission protocol, such as TCP/UDP, this default value is usually set to 0 */int sock = socket (AF_INET, SOCK_STREAM, 0); if (sock =-1) {close (sock ); NSLog (@ "socket error: % d", sock );
Return ;}
2. Bind the local address and port number
// Address structure data, record ip and port number struct sockaddr_in sockAddr; // declare the protocol used for sockAddr. sin_family = AF_INET; // obtain the ip address of the Local Machine and convert it to a char-type const char * ip = [[self getIPAddress] cStringUsingEncoding: NSASCIIStringEncoding]; // assign the ip address to the struct, the inet_addr () function converts an IP address in dotted-decimal format into a long integer number sockAddr. sin_addr.s_addr = inet_addr (ip); // set the port number. htons () converts the integer variable from the host byte sequence to the network byte sequence sockAddr. sin_port = htons (12345);/** the bind function is used to associate a socket with an address and return an int value.-1 indicates a failure * specify the socket with the first parameter, that is, the preceding socket function calls the returned socket * The second parameter is the specified address * The third parameter is the size of the address data */int bd = bind (sock, (struct sockaddr *) & sockAddr, sizeof (sockAddr); if (bd =-1) {close (sock); NSLog (@ "bind error: % d", bd); return ;}
3. Listen to the bound address
/** The listen function changes the interface for connecting to another process to be connected, so that it can accept requests from other processes and return an int value, -1: Failure * The first parameter is the socket returned by the previous socket function * The second parameter can be understood as the maximum connection limit */int ls = listen (sock, 20 ); if (ls =-1) {close (sock); NSLog (@ "listen error: % d", ls); return ;}
4. Wait for the client connection and use accept () (because the accept function will block the thread and will be stuck during the connection process, we recommend that you put it in the Child thread)
// 1. Enable a subthread NSTread * recvThread = [[NSThread alloc] initwithTarget: self selector: @ selector (recvData) object: nil]; [recvThread start]; -(void) recvData {// 2, wait for the client to connect // declare an address structure for receiving the address returned by the client struct sockaddr_in recvAddr; // address size socklen_t recv_size = sizeof (struct sockaddr_in);/** the accept () function returns a new socket (self. newSock), used to send and receive data later than the client * The first parameter is the socket of the previous listener, which is a local variable. Now you need to change it to the global * The second parameter is a result parameter, it is used to receive a return value. This return value specifies the client address. * The third parameter is also a result parameter. It is used to receive the consignment of the recvAddr struct and specify the number of bytes it occupies */self. newSock = accept (self. sock, (struct sockaddr *) & recvAddr, & recv_size); // 3. It indicates that you have connected to a new client and can send and receive data below, the send () and recv () functions ssize_t bytesRecv =-1; // return the Data byte size char recvData [128] = ""; // return to the data cache. // if one end is disconnected, the recv will return immediately. bytesrecv is equal to 0, and the while loop will be executed continuously, therefore, if the value is 0, the system jumps out while (1) {bytesRecv = recv (self. newSocket, recvData, 0); // recvData indicates the received data if (bytesRecv = 0) {break ;}}}
5. Send data
- (void)sendMessage{ char sendData[32] = "hello client"; ssize_t size_t = send(self.newSocket, sendData, strlen(sendData), 0); }
The client side is mainly divided into: Create a socket, obtain the server host address based on the ip address and port number, and then connect. After the connection is successful, data can be sent and received to the server. Let's look at the code below.
1. Use the socket function to create a socket like the server.
int sock = socket(AF_INET, SOCK_STREAM,0);if(sock == -1){ NSLog(@"socket error : %d",sock); return;}
2. Obtain the host address.
NSString * host = [self getIPAddress]; // obtain the local IP address // return the hostent structure pointer struct hostent * remoteHostEnt = gethostbyname ([host UTF8String]) corresponding to the given host name containing the host Name and address information; if (remoteHostEnt = NULL) {close (sock); NSLog (@ "unable to parse server host name"); return ;}
// Configure the IP address and port number of the host to be connected to the socket. It is used for the connect () function struct in_addr * remoteInAddr = (struct in_addr *) remoteHost-> h_addr_list [0]; struct sockaddr_in; socketPram. sin_family = AF_INT; socketPram. sin_addr = * remoteInAddr; socketPram. sin_port = htons ([port intValue]);
3. Use the connect () function to connect to the host
/** The connect function is usually used for client resume tcp connection to connect to the host with the specified address. The function returns an int value.-1 indicates failure * The first parameter is the socket created by the socket function, indicates the socket to connect to the specified host * The second parameter is the host address and port number of the socket sock to connect * The third parameter is the host address size */int con = connect (sock, (struct sockaddr *) & socketPram, sizeof (socketPram); if (con =-1) {close (sock); NSLog (@ "connection failed"); return ;} NSLog ("connection successful"); // The connection is successful;
4. After the connection is successful, you can send and receive data.
-(IBAction) senddata :( id) sender {// send data char sendData [32] = "hello service"; ssize_t size_t = send (self. sock, sendData, strlen (sendData), 0); NSLog (@ "% zd", size_t);}-(void) recvData {// accept data, put it in the sub-thread ssize_t bytesRecv =-1; char recvData [32] = ""; while (1) {bytesRecv = recv (self. sock, recvData, 32, 0); NSLog (@ "% zd % s", bytesRecv, recvData); if (bytesRecv = 0) {break ;}}}
Well, use the socket to communicate with two apps locally. I wrote a blog post for the first time. I recorded my experiences and shared my experiences with you. I hope you can point out something wrong in this article. The Demo address is attached. You can try it out for two projects if you are interested. Https://pan.baidu.com/s/1nvcvC8p