【iOS乾貨】☞ Socket,ios乾貨socket

來源:互聯網
上載者:User

【iOS乾貨】☞ Socket,ios乾貨socket
一、概念

  • Socket 字面意思又稱“通訊端”

  • 網路上的兩個程式(如,用戶端和伺服器端)通過一個雙向的通訊串連實現資料的交換,這個串連的一端稱為一個socket。

  • 應用程式一般是先通過Socket來建立一個通訊串連,再向網路發出請求或響應網路請求。

  

  說明:

    ☞ 用戶端向伺服器端發送網路請求前,必須要先在底層建立一個通訊串連(通訊管道),才能發送網路請求。

用戶端向伺服器端發送http請求,伺服器返回資料,這個過程就是一個資料交換的過程。

用戶端與伺服器端進行資料交換,需要先建立一個雙向的通訊串連(即一條線、一個通道)

    ☞ 用戶端和服務端 兩端都有一個Socket,通過Socket建立一個串連(雙向通訊管道),有了管道就可以進行資料轉送。

    ☞ Socket 就是通訊管道的兩個連接埠,可以理解為管道的入口/出口。

二、網路通訊的要素

  網路上的請求就是通過Socket來建立串連然後互相通訊

  1. IP地址(網路上主機裝置的唯一標識)——>尋找伺服器主機

  2. 連接埠號碼(定位程式) ——> 尋找程式

  3. 傳輸協議(就是用什麼樣的方式進行互動)

三、傳輸協議 TCP/UDP

  TCP和UDP:資料轉送的兩種方式,即把資料從一端傳到另一端的兩種方式

  1. TCP(傳輸控制通訊協定) —>要建立串連(如:發送HTTP請求,用戶端向服務端發送網路請求)

☞ 建立串連,形成傳輸資料的通道

☞ 在串連中進行大資料轉送(資料大小不受限制)

☞ 通過三向交握完成串連,是可靠協議,安全送達

        說明:在建立通訊串連(打通管道)之前有三向交握,目的是為了資料的安全性和可靠性(讓資料安全可靠的傳輸到對方)。

        舉例:打電話 (理解三向交握)

第一次握手:拿起電話,進行撥號。這個撥號的過程稱為第一次握手。【開始準備串連】

第二次握手:撥通了,對方"喂"了一聲(響應了一聲),我聽到了,稱為第二次握手。【說明我串連你 沒問題】

第三向交握:我聽到了對方"喂"了一聲(響應了一聲),我也習慣性的"喂"了一聲,對方聽到了。【說明你串連我 沒問題】

如果這三個過程都沒有問題,就可以確定通話串連建立成功。

    ☞ 必須建立串連,效率會稍低。(每次請求都要建立串連)

 

  2. UDP(使用者資料包通訊協定)—>不建立串連 (如:廣播用這個,不斷的發送資料包)

    ☞ 將 資料 及 源 和 目的 封裝成資料包中,不需要建立串連

    ☞ 每個資料報的大小限制在64KB之內

    ☞ 因為無需串連,因此是不可靠協議

      舉例:看老師廣播講課,網路卡主了,再看到的是最新的視頻內容,不能接著看,可能錯過了一些內容。

    ☞ 不需要建立串連,速度快 (省掉了三向交握操作)

四、Socket通訊流程圖

☞ bind():綁定連接埠 (80、3306)

☞ listen():監聽連接埠(伺服器監聽用戶端有沒有串連到這個連接埠來)

☞ accept():如果有串連到這個連接埠,就接收這個串連。(通訊管道打通,接下來就可以傳輸資料了)

☞ write():發請求/寫請求/發資料

☞ read():讀請求/讀資料

  • HTTP底層就是Socket通訊,通過Socket建立串連(通訊管道),實現資料轉送,串連的方式(資料轉送的方式)是TCP。
  • HTTP是一個TCP的傳輸協議(方式),它是一個可靠、安全的協議。

五、體驗Socket  

  實現Socket服務端監聽:

1)使用C語言實現。

2)使用 CocoaAsyncSocket 第三方架構(OC),內部是對C的封裝。

 

  telnet命令:是串連伺服器上的某個連接埠對應的服務。

  telnet命令:telnet host port 

    如:telnet www.baidu.com 80  (IP地址和網域名稱一樣,都能找到主機。)

 

1. 【案例】寫個10086服務,體驗用戶端與服務端的Socket通訊

☞ 自己寫一個服務端,用終端代替用戶端來示範

☞ 掌握:通過Socket對象在伺服器裡怎麼去接收資料和返回資料。

     

/// ----- MyServiceListener.h -----@interface MyServiceListener : NSObject//開啟服務- (void)start;@end/// ----- MyServiceListener.m -----#import "MyServiceListener.h"#import "GCDAsyncSocket.h"/** * 服務的監聽者(服務端監聽用戶端串連) */@interface MyServiceListener()<GCDAsyncSocketDelegate>/** 儲存服務端的Socket對象 */@property (nonatomic, strong) GCDAsyncSocket *serviceSocket;/** 儲存用戶端的所有Socket對象 */@property (nonatomic, strong) NSMutableArray *clientSocketArr;@end@implementation MyServiceListener- (GCDAsyncSocket *)serviceSocket { if (!_serviceSocket) { //1.建立一個Socket對象 //serviceSocket 服務端的Socket只監聽 有沒有用戶端請求串連 //隊列:代理的方法在哪個隊列裡調用 (子線程的隊列) _serviceSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)]; } return _serviceSocket;}- (NSMutableArray *)clientSocketArr { if(!_clientSocketArr) { _clientSocketArr = [NSMutableArray array]; } return _clientSocketArr;}- (void)start { //開啟10086服務:5288 //2.綁定連接埠 + 開啟監聽 NSError *error = nil; //架構裡的這個方法做了兩件事情:綁定連接埠和開啟監聽 [self.serviceSocket acceptOnPort:5288 error:&error]; if (!error) { NSLog(@"10086服務開啟成功!"); } else { //失敗的原因是連接埠被其它程式佔用 NSLog(@"10086服務開啟失敗:%@", error); } }#pragma mark -- 實現代理的方法 如果有用戶端的Socket串連到伺服器,就會調用這個方法。- (void)socket:(GCDAsyncSocket *)serviceSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket { static NSInteger index = 1; NSLog(@"用戶端【%ld】已串連到伺服器!", index++); //1.儲存用戶端的Socket(用戶端的Socket被釋放了,串連就會關閉) [self.clientSockets addObject:clientSocket]; //提供服務(用戶端一串連到伺服器,就列印下面的內容) NSMutableString *serviceStr = [[NSMutableString alloc]init]; [serviceStr appendString:@"========歡迎來到10086線上服務========\n"]; [serviceStr appendString:@"請輸入下面的數字選擇服務...\n"]; [serviceStr appendString:@" [0] 線上儲值\n"]; [serviceStr appendString:@" [1] 線上投訴\n"]; [serviceStr appendString:@" [2] 優惠資訊\n"]; [serviceStr appendString:@" [3] special services\n"]; [serviceStr appendString:@" [4] 退出\n"]; [serviceStr appendString:@"=====================================\n"]; // 服務端給用戶端發送資料 [clientSocket writeData:[serviceStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]; //2.監聽用戶端有沒有資料上傳 (參數1:逾時時間,-1代表不逾時) /** * timeout: 逾時時間,-1 代表不逾時 * tag:標識作用,現在不用就寫0 */ [clientSocket readDataWithTimeout:-1 tag:0];}#pragma mark -- 伺服器端 讀取 用戶端請求(發送)的資料。在服務端接收用戶端資料,這個方法會被調用- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag { //1.擷取用戶端發送的資料 NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSInteger index = [self.clientSocketArr indexOfObject:clientSocket]; NSLog(@"接收到用戶端【%ld】發送的資料:%@", index + 1, str); //把字串轉成數字 NSInteger num = [str integerValue]; NSString *responseStr = nil; //伺服器對應的處理的結果 switch (num) { case 0: responseStr = @"線上儲值服務暫停中...\n"; break; case 1: responseStr = @"線上投訴服務暫停中...\n"; break; case 2: responseStr = @"優惠資訊沒有\n"; break; case 3: responseStr = @"沒有特殊服務\n"; break; case 4: responseStr = @"恭喜你退出成功!\n"; break; default: break; } //2.服務端處理請求,返回資料(data)給用戶端 [clientSocket writeData:[responseStr dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0]; //寫完資料後 判斷 if (num == 4) { //移除用戶端,就會關閉串連 [self.clientSockets removeObject:clientSocket]; } //由於架構內部的實現,每次讀完資料後,都要調用一次監聽資料的方法(保證能接收到用戶端第二次上傳的資料) [clientSocket readDataWithTimeout:-1 tag:0]; }@end/// ----- ViewController.m -----#import "ViewController.h"#import "MyServiceListener.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; //1.建立一個服務監聽對象 MyServiceListener *listener = [[MyServiceListener alloc]init]; //2.開始監聽 [listener start]; //3.開啟主運行迴圈,讓服務不能停(伺服器一般要永久開啟) [[NSRunLoop mainRunLoop] run]; }@end體驗Socket通訊-服務端簡單實現代碼2. 【案例擴充】寫個轉寄Message Service(群聊服務端)
  • 多個用戶端串連到伺服器。
  • 當一個用戶端發送訊息給伺服器時,伺服器轉寄給其它已經串連的用戶端。
  • 相當於一個群聊的雛形。

  

/// MyService.h#import <Foundation/Foundation.h>@interface MyService : NSObject/** 開啟服務 */- (void)startService;@end/// MyService.m#import "MyService.h"#import "GCDAsyncSocket.h"@interface MyService ()<GCDAsyncSocketDelegate>/** 儲存服務端的Socket對象 */@property (nonatomic, strong) GCDAsyncSocket *serviceSocket;/** 儲存用戶端的所有Socket對象 */@property (nonatomic, strong) NSMutableArray *clientSocketArr;@end@implementation MyService//開啟10086服務:5288- (void)startService { NSError *error = nil; // 綁定連接埠 + 開啟監聽 [self.serviceSocket acceptOnPort:5288 error:&error]; if (!error) { NSLog(@"服務開啟成功!"); } else { NSLog(@"服務開啟失敗!"); }}#pragma mark -- 實現代理的方法 如果有用戶端的Socket串連到伺服器,就會調用這個方法。- (void)socket:(GCDAsyncSocket *)serviceSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket { // 用戶端的連接埠號碼是系統分配的,服務端的連接埠號碼是我們自己分配的 NSLog(@"用戶端【Host:%@, Port:%d】已串連到伺服器!", clientSocket.connectedHost, clientSocket.connectedPort); //1.儲存用戶端的Socket(用戶端的Socket被釋放了,串連就會關閉) [self.clientSocketArr addObject:clientSocket]; //2.監聽用戶端有沒有資料上傳 (參數1:逾時時間,-1代表不逾時;參數2:標識作用,現在不用就寫0) [clientSocket readDataWithTimeout:-1 tag:0];}#pragma mark -- 伺服器端 讀取 用戶端請求(發送)的資料。在服務端接收用戶端資料,這個方法會被調用- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag { //1.擷取用戶端發送的資料 NSString *messageStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"接收到用戶端【Host:%@, Port:%d】發送的資料:%@", clientSocket.connectedHost, clientSocket.connectedPort, messageStr); // 遍曆用戶端數組 for (GCDAsyncSocket *socket in self.clientSocketArr) { if (socket != clientSocket) { // 不轉寄給自己 //2.服務端把收到的訊息轉寄給其它用戶端 [socket writeData:data withTimeout:-1 tag:0]; } } //由於架構內部的實現,每次讀完資料後,都要調用一次監聽資料的方法(保證能接收到用戶端第二次上傳的資料) [clientSocket readDataWithTimeout:-1 tag:0];}- (GCDAsyncSocket *)serviceSocket { if (!_serviceSocket) { // 1.建立一個Socket對象 // serviceSocket 服務端的Socket只監聽 有沒有用戶端請求串連 // 隊列:代理的方法在哪個隊列裡調用 (子線程的隊列) _serviceSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)]; } return _serviceSocket;}- (NSMutableArray *)clientSocketArr { if (!_clientSocketArr) { _clientSocketArr = [[NSMutableArray alloc]init]; } return _clientSocketArr;}@end/// main.m#import <Foundation/Foundation.h>#import "MyService.h"int main(int argc, const char * argv[]) { @autoreleasepool { //1.建立一個服務監聽對象 MyService *service = [[MyService alloc]init]; //2.開始監聽 [service startService]; //3.開啟主運行迴圈,讓服務不能停(伺服器一般要永久開啟) [[NSRunLoop mainRunLoop] run]; } return 0;}體驗Socket通訊-群聊服務端實現代碼:

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.