English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
以前、アプリ間の通信方法について紹介している記事を見つけました。それには、URL Scheme、Keychain、UIPasteboard、UIDocumentInteractionController、そしてローカル通信にsocketを使用する方法があります。前4これらの方法はどれも使ったことがあります。比較的簡単で、数行のコードで済みます。最後の方法は、私が使ったことがなかったので(私も初心者です)、今日は試してみました。ここに記録しておいて、皆さんに共有します。
それでは、余計なことを言わずに始めましょう:
まずはその原理について説明します。実は非常にシンプルで、アプリがローカルのポートでTCPのbindとlistenを行い、もう一つのアプリが同じポートでconnectを行うと、正常なTCP接続が確立され、どんなデータでも送信できます。まず、サーバーサイドの作成から始めましょう:
1,首先用socket()函数创建一个套接字
/* * socket返回一个int值,-1为创建失败 * 第一个参数指明了协议族/域 ,通常有AF_INET(IPV4)、AF_INET6)、IPV6)、AF_LOCAL * 第二个参数指定一个套接口类型:SOCK_STREAM,SOCK_DGRAM、SOCK_SEQPACKET等 * 第三个参数指定相应的传输协议,诸如TCP/UDP等,一般设置为0来使用这个默认的值 */ int sock = socket(AF_INET, SOCK_STREAM, 0); if(sock == -1{ close(sock); NSLog(@"socket error : %d",sock);<br> return; }
2,綁定本機地址和端口号
// 地址結構體數據,記錄ip和端口号 struct sockaddr_in sockAddr; // 声明使用的協議 sockAddr.sin_family = AF_INET; // 获取本机的ip,转换成char类型的 const char *ip = [[self getIPAddress] cStringUsingEncoding:NSASCIIStringEncoding]; // 將ip賦值給結構體,inet_addr()函数是将一个点分十进制的IP转换成一个长整数型数 sockAddr.sin_addr.s_addr = inet_addr(ip); // 设置端口号,htons()是将整型变量从主机字节顺序转变成网络字节顺序 sockAddr.sin_port = htons(12345; /* * bind函数用于將套接字關聯一個地址,返回一个int值,-1为失败 * 第一个参数指定套接字,就是前面socket函数调用返回的套接字 * 第二个参数为指定的地址 * 第三个参数为地址数据的大小 */ int bd = bind(sock,(struct sockaddr *) &sockAddr, sizeof(sockAddr)); if(bd == -1{ close(sock); NSLog(@"bind error : %d",bd); return; }
3,監聽綁定的地址
/* * listen函数使用主动连接套接接口变为被连接接口,使得可以接受其他进程的請求,返回一个int值,-1为失败 * 第一个参数是之前socket函数返回的套接字 * 第二个参数可以理解为连接的最大限制 */ int ls = listen(sock,2,0); if(ls == -1{ close(sock); NSLog(@"listen error : %d",ls); return; }
4、以下でクライアントの接続を待ちます、accept()を使用します(accept関数はスレッドをブロックするため、接続待ちの間にスレッドがずっと停止するため、サブスレッドに配置することをお勧めします)
// 1、サブスレッドを開始します NSTread *recvThread = [[NSThread alloc] initwithTarget:self selector:@selector(recvData) object: nil]; [recvThread start]; - (void)recvData{ // 2,クライアントの接続を待つ // アドレス構造体を宣言し、後にクライアントからの返信アドレスを受け取るために使用します struct sockaddr_in recvAddr; // アドレスサイズ socklen_t recv_size = sizeof(struct sockaddr_in); /* * accept()関数が接続成功すると、新しいソケット(self.newSock)が返され、そのクライアントとのデータの送受信に使用されます * 第1引数は前にリスニングしていたソケットであり、以前はローカル変数であったが、今はグローバルに変更する必要があります * 第2引数も結果引数であり、返り値を受け取り、その返り値はクライアントのアドレスを指定します * 第3引数も結果引数であり、recvAddr構造体の指針を受け取り、その占有するバイト数を示します */ self.newSock = accept(self.sock,(struct sockaddr *) &recvAddr, &recv_size); // 3、ここに来たら新しいクライアントに接続されていることを意味し、以下でデータの送受信を行うことができます、主にsend()とrecv()関数を使用します ssize_t bytesRecv = -1; // 返信データバイトサイズ char recvData[128] = ""; // 返信データキャッシュエリア // 接続が切れた場合、recvはすぐに返り値を返し、bytesrecvは0に等しくなり、その後whileループは無限に実行されるため、0に等しいことをチェックしてループから飛び出す while(1{ bytesRecv = recv(self.newSocket,recvData,128,0); // recvDataが受け取ったデータ if(bytesRecv == 0){ break; } } }
5、送信データ
- (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エラー : %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(@"接続失敗"); return; } NSLog("接続成功"); // これに到達したことは接続が成功したことを意味します;
4、接続が成功した後、データの送受信が可能になります}}
- (IBAction)senddata:(id)sender { // データを送信する char sendData[32] = "hello service"; ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0); NSLog(@"%zd",size_t); } - (void)recvData{ // データを受け取る、サブスレッドに置く 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; } } }
本地でsocketを使用して2つのAppの通信を行うのはこれで完了です。初めてのブログ記事ですが、自分の体験を記録し、皆さんと共有するためです。文章に誤りがあれば、ご指摘いただけると幸いです。最後にDemoのURLを付けて、興味がある方はダウンロードして試してみてください。
https://pan.baidu.com/s/1nvcvC8p
これがiOS App間の通信 - local socket の情報収集です。今後も関連する情報を追加していく予定です。皆様のこのサイトへのサポートに感謝します!
声明:この記事の内容はインターネットから収集され、著作権者に帰属します。インターネットユーザーによって自発的に提供され、自己でアップロードされました。このサイトは所有権を持ちません。人工編集は行われていません。また、関連する法的責任も負いません。著作権侵害が疑われる場合は、メール:notice#wまでご連絡ください。3codebox.com(メールを送信する際には、#を@に変更してください。侵权を報告する場合は、関連する証拠を提供し、確認された場合は、このサイトが即座に侵害された内容を削除します。)