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

Communication entre les applications iOS via local socket

Avant, j'ai vu un article qui présente les cinq méthodes de communication entre les applications, à savoir URL Scheme, Keychain, UIPastedboard, UIDocumentInteractionController et la communication locale utilisant socket. Avant4toutes les deux ont été utilisées, et elles sont relativement simples, cela ne prend que quelques lignes de code. Pour la dernière, je n'avais jamais utilisé avant (pardon, je suis encore un débutant), donc aujourd'hui, j'ai essayé d'écrire un peu, et je l'ai enregistré ici pour partager avec vous. 

Très bien, sans plus attendre, commençons : 

D'abord, expliquons son principe, c'est en fait très simple, une application bind et listen sur le port local, et une autre application se connecte sur le même port local, ce qui établit une connexion TCP normale, et vous pouvez envoyer ce que vous voulez de données. Commençons par créer le serveur : 

1、d'abord utiliser la fonction socket() pour créer un socket}} 

/*
* socket retourne une valeur int,-1Pour la création échouée
* Le premier paramètre indique la famille de protocole/Domaine, généralement AF_INET(IPV4)、AF_INET6)、AF_INET6)、AF_LOCAL
* Le deuxième paramètre spécifie un type de socket : SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc.
* Le troisième paramètre spécifie le protocole de transmission correspondant, tels que TCP/UDP, etc., généralement réglé sur 0 pour utiliser cette valeur par défaut
*/
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
close(sock);
NSLog(@"erreur de socket : %d",sock);<br> return;
}
/*
 * socket retourne une valeur int,-1Pour la création échouée
 * Le premier paramètre indique la famille de protocole/Domaine, généralement AF_INET(IPV4)、AF_INET6)、AF_INET6)、AF_LOCAL
 * Le deuxième paramètre spécifie un type de socket : SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, etc.
 * Le troisième paramètre spécifie le protocole de transmission correspondant, tels que TCP/UDP, etc., généralement réglé sur 0 pour utiliser cette valeur par défaut
 */
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == -1){
 close(sock);
 NSLog(@"erreur de socket : %d",sock);<br> return;
}

2、lier l'adresse et le port de l'ordinateur local 

// Données de structure d'adresse, enregistrer l'ip et le port
struct sockaddr_in sockAddr;
// Déclarer le protocole utilisé
sockAddr.sin_family = AF_INET;
// Obtenir l'ip de l'ordinateur local, converti en type char
const char *ip = [[self getIPAddress] cStringUsingEncoding:NSASCIIStringEncoding];
// Affecter l'ip à la structure, inet_addr() est la conversion d'une IP en point décimal en un entier long
sockAddr.sin_addr.s_addr = inet_addr(ip);
// Définir le port, htons() est la conversion d'un variable de type int du ordre des octets de l'hôte vers l'ordre des octets réseau
sockAddr.sin_port = htons(12345;
/*
 * La fonction bind est utilisée pour associer un adresse au socket, et retourne une valeur int,-1为失败
 * Le premier paramètre spécifie le socket, c'est le socket retourné par l'appel de la fonction socket précédemment
 * Le deuxième paramètre est l'adresse spécifiée
 * Le troisième paramètre est la taille des données d'adresse
 */
int bd = bind(sock,(struct sockaddr *) &sockAddr, sizeof(sockAddr));
if(bd == -1){
 close(sock);
 NSLog(@"erreur de bind : %d",bd);
 return;
}

3、écouter l'adresse de liaison

/*
 * La fonction listen utilise l'interface de socket de connexion active pour devenir une interface de connexion passée, ce qui permet d'accepter les demandes d'autres processus, et retourne une valeur int,-1为失败
 * Le premier paramètre est le descripteur de socket renvoyé par la fonction socket
 * Le deuxième paramètre peut être compris comme la limitation maximale de connexion
 */
int ls = listen(sock,2,0);
if(ls == -1){
 close(sock);
 NSLog(@"erreur d'écoute : %d",ls);
 return;
}

4、attendre la connexion du client, utiliser accept()(puisque la fonction accept() bloquera le thread, pendant la période d'attente de la connexion, il restera coincé, donc il est recommandé de le mettre dans un sous-thread) 

// 1.ouvrir un sous-thread
NSTread *recvThread = [[NSThread alloc] initwithTarget:self selector:@selector(recvData) object: nil];
[recvThread start];
- (void)recvData{
// 2.attendre la connexion du client
// Déclarer une structure d'adresse, utilisée pour recevoir l'adresse renvoyée par le client après 
 struct sockaddr_in recvAddr;
// taille de l'adresse
 socklen_t recv_size = sizeof(struct sockaddr_in);
/*
 * La fonction accept() renvoie un nouveau descripteur de socket (self.newSock) après une connexion réussie, utilisé pour envoyer et recevoir des données avec ce client
 * Le premier paramètre est le descripteur de socket en écoute, qui était une variable locale auparavant, maintenant il doit être modifié en variable globale
 * Le deuxième paramètre est un paramètre de résultat, utilisé pour recevoir une valeur de retour, cette valeur de retour spécifie l'adresse du client
 * Le troisième paramètre est également un paramètre de résultat, utilisé pour recevoir le délégué de la structure recvAddr, indiquant le nombre d'octets qu'elle occupe
 */
self.newSock = accept(self.sock,(struct sockaddr *) &recvAddr, &recv_size);
// 3.Arriver ici signifie que nous sommes déjà connectés à un nouveau client, nous pouvons donc commencer à envoyer et recevoir des données, principalement en utilisant les fonctions send() et recv()
 ssize_t bytesRecv = -1; // retourner la taille des octets des données
 char recvData[128] = ""; // retourner la zone de cache des données
// Si un extrémité rompt la connexion, recv revient immédiatement, bytesrecv vaut 0, puis la boucle while continue de s'exécuter, donc juger égale à 0 est sauter
 while(1){
 bytesRecv = recv(self.newSocket,recvData,128,0); // recvData est les données reçues
 if(bytesRecv == 0){
 break; 
 }
 }
}

5、envoyer des données 

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

客户端这边主要分为:创建套接字,根据ip和端口号获取服务端的主机地址,然后再连接,连接成功后就能够向服务端收发数据了,下面我们看代码。 

1、和服务端一样用socket函数创建套接字 

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

2、获取主机的地址 

NSString *host = [self getIPAddress]; // 获取本机ip地址
// 返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针
struct hostent *remoteHostEnt = gethostbyname([host UTF8String]);
if(remoteHostEnt == NULL){
 close(sock);
 NSLog(@"无法解析服务器主机名");
 return;
}// 配置套接字将要连接主机的ip地址和端口号,用于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、使用connect()函数连接主机 

/*
 * connect函数通常用于客户端建立tcp连接,连接指定地址的主机,函数返回一个int值,-1为失败
 * 第一个参数为socket函数创建的套接字,代表这个套接字要连接指定主机
 * 第二个参数为套接字sock想要连接的主机地址和端口号
 * 第三个参数为主机地址大小
 */
int con = connect(sock, (struct sockaddr *) &socketPram, sizeof(socketPram));
if(con == -1){
 close(sock);
 NSLog(@"Échec de la connexion");
 return;
}
NSLog("Connexion réussie"); // Vous êtes ici, ce qui signifie que la connexion a réussi

4Après la connexion réussie, vous pouvez envoyer et recevoir des données 

- (IBAction)senddata:(id)sender {
 // Envoyer des données
 char sendData[32] = "hello service";
 ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0);
 NSLog(@"%zd",size_t);
}
- (void)recvData{
 // Recevoir des données, les mettre dans un sous-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;
  }
 }
}

C'est tout pour la communication entre deux applications locales en utilisant socket. C'est ma première fois d'écrire un article, d'une part pour enregistrer mes réflexions, d'autre part pour partager avec vous, j'espère que vous pouvez indiquer les erreurs dans l'article. Enfin, je joins l'adresse du Demo, deux projets, ceux qui sont intéressés peuvent les télécharger et essayer :

Voici la fin de cet article, j'espère qu'il vous sera utile dans vos études, et j'espère que vous serez nombreux à soutenir le tutoriel de cri.

Déclaration : Le contenu de cet article est tiré du réseau, propriété de l'auteur original, contribué et téléchargé par les utilisateurs d'Internet de manière spontanée. Ce site ne détient pas de droits de propriété, n'a pas été édité par l'homme, et n'assume aucune responsabilité juridique connexe. Si vous trouvez du contenu suspect de violation de droits d'auteur, n'hésitez pas à envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.).

Vous pourriez aussi aimer