English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Comunicazione tra applicazioni iOS tramite local socket

Ho letto un articolo che introduceva cinque modi di comunicazione tra applicazioni, che sono rispettivamente URL Scheme, Keychain, UIPastedboard, UIDocumentInteractionController e comunicazione locale utilizzando socket. Le prime quattro sono state utilizzate, sono anche relativamente semplici, è sufficiente poche righe di codice. Per l'ultimo modo non l'avevo mai utilizzato (scusate se sono ancora un principiante), quindi oggi ho cercato di scriverlo, qui lo registro e lo condivido con tutti. 

Bene, senza perdere tempo, iniziamo: 

Prima di tutto, parliamo del suo principio, in realtà è molto semplice, un'applicazione locale si connette al proprio porto in TCP tramite bind e listen, un'altra applicazione locale si connette al medesimo porto tramite connect, in questo modo si stabilisce una connessione TCP normale, si può trasmettere qualsiasi tipo di dati. Iniziamo con la creazione del server: 

1、prima di tutto, utilizzare la funzione socket() per creare un socket 

/*
* socket restituisce un valore int, -1 indica un fallimento nella creazione
* Il primo parametro indica la famiglia di protocollo/ dominio, di solito AF_INET(IPV4), AF_INET6(IPV6), AF_LOCAL
* Il secondo parametro specifica un tipo di socket: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET ecc.
* Il terzo parametro specifica il protocollo di trasmissione corrispondente, come TCP/UDP ecc., generalmente impostato a 0 per utilizzare questo valore predefinito
*/
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
close(sock);
NSLog(@"errore di socket : %d", sock);<br> return;
}
/*
 * socket restituisce un valore int, -1 indica un fallimento nella creazione
 * Il primo parametro indica la famiglia di protocollo/ dominio, di solito AF_INET(IPV4), AF_INET6(IPV6), AF_LOCAL
 * Il secondo parametro specifica un tipo di socket: SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET ecc.
 * Il terzo parametro specifica il protocollo di trasmissione corrispondente, come TCP/UDP ecc., generalmente impostato a 0 per utilizzare questo valore predefinito
 */
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
 close(sock);
 NSLog(@"errore di socket : %d", sock);<br> return;
}

2、Associare l'indirizzo e il numero di porta del computer locale 

// Struttura di dati di indirizzo, registra l'indirizzo IP e il numero di porta
struct sockaddr_in sockAddr;
// Dichiarazione del protocollo utilizzato
sockAddr.sin_family = AF_INET;
// Ottieni l'indirizzo IP del computer, convertito in tipo char
const char *ip = [[self getIPAddress] cStringUsingEncoding:NSASCIIStringEncoding];
// Assegna l'indirizzo IP alla struttura, inet_addr() è la conversione di un indirizzo IP in virgola decimale in un intero a lunghezza di 32 bit
sockAddr.sin_addr.s_addr = inet_addr(ip);
// Imposta il numero di porta, htons() è la conversione da variabile intera in ordine di byte di host a ordine di byte di rete
sockAddr.sin_port = htons(12345);
/*
 * La funzione bind utilizza il socket per associare un indirizzo, restituendo un valore int, -1 per fallimento
 * Il primo parametro specifica il socket, ossia il socket restituito dalla chiamata alla funzione socket
 * Il secondo parametro è l'indirizzo specificato
 * Il terzo parametro è la dimensione dei dati di indirizzo
 */
int bd = bind(sock,(struct sockaddr *) &sockAddr, sizeof(sockAddr));
if(bd == -1){
 close(sock);
 NSLog(@"errore di binding : %d",bd);
 return;
}

3、Ascoltare l'indirizzo di binding

/*
 * La funzione listen utilizza un socket di connessione attiva per diventare un socket di connessione passiva, permettendo di accettare richieste da altri processi, restituendo un valore int, -1 per fallimento
 * Il primo parametro è il socket restituito dalla funzione socket
 * Il secondo parametro può essere interpretato come il limite massimo di connessioni
 */
int ls = listen(sock,20);
if(ls == -1){
 close(sock);
 NSLog(@"errore di ascolto : %d",ls);
 return;
}

4、Ecco l'attesa della connessione del client, utilizzando accept()(dato che la funzione accept() blocca il thread, nel processo di attesa della connessione rimarrà bloccato, quindi si consiglia di metterlo in un sottothread) 

// 1. Avvia un sottothread
NSTread *recvThread = [[NSThread alloc] initwithTarget:self selector:@selector(recvData) object: nil];
[recvThread start];
- (void)recvData{
// 2. Attendere la connessione del client
// Dichiarazione di una struttura di indirizzo, utilizzata per ricevere l'indirizzo del client in seguito 
 struct sockaddr_in recvAddr;
// Dimensione dell'indirizzo
 socklen_t recv_size = sizeof(struct sockaddr_in);
/*
 * La funzione accept() restituisce un nuovo socket (self.newSock) dopo che la connessione è stata stabilita, utilizzato per comunicare con questo client
 * Il primo parametro è il socket in ascolto, che prima era una variabile locale, ora deve essere resa globale
 * Il secondo parametro è un parametro di risultato, utilizzato per ricevere un valore di ritorno, che specifica l'indirizzo del client
 * Il terzo parametro è anche un parametro di risultato, utilizzato per ricevere il valore di back di recvAddr, che indica la dimensione in byte
 */
self.newSock = accept(self.sock,(struct sockaddr *) &recvAddr, &recv_size);
// 3. Arrivati qui significa che è stata stabilita una connessione con un nuovo client, quindi è possibile procedere con l'invio e la ricezione dei dati, utilizzando principalmente le funzioni send() e recv()
 ssize_t bytesRecv = -1; // Dimensione dei byte dei dati di ritorno
 char recvData[128] = ""; // Area di cache dei dati di ritorno
// Se una delle estremità chiude la connessione, recv ritorna immediatamente, bytesrecv è uguale a 0, quindi il ciclo while continua a eseguire, quindi la condizione uguale a 0 è uscire dal ciclo
 while(1){
 bytesRecv = recv(self.newSocket,recvData,128,0); // recvData è i dati ricevuti
 if(bytesRecv == 0){
 break; 
 }
 }
}

5、Invio dei dati 

- (void)sendMessage{ 
 char sendData[32] = "hello client";
 ssize_t size_t = send(self.newSocket, sendData, strlen(sendData), 0);
}

Sul lato client, la procedura principale si suddivide in: creazione del socket, recupero dell'indirizzo del server tramite IP e porta, quindi connessione, e una volta stabilita la connessione, è possibile inviare e ricevere dati dal server. Di seguito vediamo il codice. 

1、Creare un socket utilizzando la funzione socket come il server 

int sock = socket(AF_INET, SOCK_STREAM,0);
if(sock == -1){
 NSLog(@"Errore socket : %d",sock);
 return;
}

2、Ottenere l'indirizzo dell'host 

NSString *host = [self getIPAddress]; // Ottenere l'indirizzo IP locale
// Restituisce un puntatore alla struttura hostent che contiene il nome e l'indirizzo dell'host specificato
struct hostent *remoteHostEnt = gethostbyname([host UTF8String]);
if(remoteHostEnt == NULL){
 close(sock);
 NSLog(@"Impossibile risolvere il nome host del server");
 return;
<br>// Configurare l'indirizzo IP e il numero di porta dell'host che il socket deve connettersi, utilizzato dalla funzione connect()
struct in_addr *remoteInAddr = (struct in_addr *)remoteHost->h_addr_list[0];
struct sockaddr_in socktPram;
socketPram.sin_family = AF_INT;
socketPram.sin_addr = *remoteInAddr;
socketPram.sin_port = htons([port intValue]);

3、Utilizzare la funzione connect() per connettersi all'host 

/*
 * La funzione connect viene solitamente utilizzata per stabilire una connessione TCP client-side, connettersi a un host specifico, la funzione restituisce un valore int, -1 per fallimento
 * Il primo parametro è il socket creato dalla funzione socket, rappresenta il socket che deve connettersi a un host specifico
 * Il secondo parametro è l'indirizzo host e il numero di porta che il socket sock desidera connettersi
 * La terza parametro è la dimensione dell'indirizzo host
 */
int con = connect(sock, (struct sockaddr *) &socketPram, sizeof(socketPram));
if(con == -1){
 close(sock);
 NSLog(@"Connessione fallita");
 return;
}
NSLog("Connessione riuscita"); // Arrivati a questo punto significa che la connessione è riuscita;

4, dopo che la connessione è stata stabilita, è possibile ricevere e inviare dati 

- (IBAction)senddata:(id)sender {
 // Invio dati
 char sendData[32] = "hello service";
 ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0);
 NSLog(@"%zd",size_t);
}
- (void)recvData{
 // Ricezione dati, messi in un thread secondario
 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;
  }
 }
}

Bene, la comunicazione tra due App locali utilizzando socket è così semplice. È la prima volta che scrivo un post, da una parte per registrare le mie esperienze, e dall'altra per condividerle con tutti voi. Spero che possiate indicarmi eventuali errori nel testo. Infine, allego l'indirizzo del Demo, due progetti, chi è interessato può scaricarli e provarli:

Questo è tutto il contenuto dell'articolo, spero che sia utile per la tua apprendimento, e spero che tutti voi possiate sostenere e gridare il tutorial.

Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, di proprietà dei rispettivi autori, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene i diritti di proprietà, non è stato sottoposto a modifica editoriale umana e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, sei invitato a inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito rimuoverà immediatamente il contenuto sospetto di violazione del copyright.

Ti potrebbe interessare