iOS App之間的通訊 local socket_IOS

來源:互聯網
上載者:User

之前看到一篇文章介紹到App之間的五種通訊方式,它分別有URL Scheme,Keychain,UIPastedboard,UIDocumentInteractionController以及利用socket進行本地通訊。前面4種都有用到過,也相對比較簡單,幾行代碼的事。對於最後一種之前一直沒用到過(原諒我還是個小白),所以今天試著寫了下,這兒記錄在這裡和大家分享。 

好了,廢話不多說,開始: 

首先,說下它的原理,其實很簡單,一個App在本地的連接埠進行TCP的bind和listen,另外一個App在本地同一個連接埠進行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;}/* * 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,20);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),用於之後和這個用戶端之前收發資料 * 第一個參數為之前監聽的通訊端,之前是局部變數,現在需要改為全域的 * 第二個參數是一個結果參數,它用來接收一個傳回值,這個傳回值指定用戶端的地址 * 第三個參數也是一個結果參數,它用來接收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 error : %d",sock); return;}

2、擷取主機的地址 

NSString *host = [self getIPAddress]; // 擷取本機ip地址// 返回對應於給定主機名稱的包含主機名稱字和地址資訊的hostent結構指標struct hostent *remoteHostEnt = gethostbyname([host UTF8String]);if(remoteHostEnt == NULL){ close(sock); NSLog(@"無法解析伺服器主機名稱"); return;}<br>// 配置通訊端將要串連主機的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在本地進行兩個App的通訊就這樣就行了。第一次寫博文,一是記錄下自己的心得,二是和大家一起分享,文中有不對的地方希望大家可以指出。最後附上Demo的地址,兩個項目,有興趣的大家可以下下來試下:

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.