Socket在百度百科的定義 網路上的兩個程式通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。 相關的描述 Socket的英文原義是“孔”或“插座”。作為BSD UNIX的進程通信機制,取後一種意思。通常也稱作"套接字",用於描述IP地址和埠,是一個通信鏈的句柄,可以用來 ...
Socket在百度百科的定義
網路上的兩個程式通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。
相關的描述
Socket的英文原義是“孔”或“插座”。作為BSD UNIX的進程通信機制,取後一種意思。通常也稱作"套接字",用於描述IP地址和埠,是一個通信鏈的句柄,可以用來實現不同虛擬機或不同電腦之間的通信。
在Internet上的主機一 般運行了多個服務軟體,同時提供幾種服務。每種服務都打開一個Socket,並綁定到一個埠上,不同的埠對應於不同的服務。
Socket正如其英文原意那樣,像一個多孔插座。一臺主機猶如佈滿各種插座的房間,每個插座有一個編號,有的插座提供220伏交流電, 有的提供110伏交流電,有的則提供有線電視節目。 客戶軟體將插頭插到不同編號的插座,就可以得到不同的服務。
正如上述的介紹Socket一定包含了通信的雙發,即客戶端(Client)與服務端(server)。
-
伺服器利用Socket監聽埠
-
客戶端發起連接
-
服務端返回信息,建立連接,開始通信
-
客戶端,服務端斷開連接
Socket 第三方 GCDAsyncSocket 的下載地址:https://github.com/AlonerOwl/socket
一、伺服器端:
在伺服器端構建的時候,我們需要導入第三方框架和其他的一些C語言包
#import "GCDAsyncSocket.h" #include <arpa/inet.h> #include <net/if.h> #include <ifaddrs.h>
1、聲明一個 socket 併進行初始化 socket
/// 伺服器端socket,決定不能使用局部變數,不能被銷毀 @property (nonatomic, strong) GCDAsyncSocket *socket; // 初始化socket self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
2、綁定埠,監聽連接消息
埠號設置:埠號大於1024,不能使用市面上已經被占用的斷開 eg.8080,8800,因此在綁定時,要進行一個安全判斷。
NSError *error; // 綁定埠,監聽連接消息 BOOL result = [self.socket acceptOnPort:[self.portTextField intValue] error:&error];
3、監聽客戶端,獲取新的socket連接之後調用以下方法,併進行一些邏輯處理
// 參數1:當前伺服器的socket // 參數2:接收到的客戶端的新socket - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
4、讀取消息
讀取方法是哪個socket調用就讀取哪個socket的攜帶消息(對應的是客戶端發送消息)
// -1 不限定讀取時間,tag為一個標記值 [newSocket readDataWithTimeout:-1 tag:0];
5、寫數據
寫給誰就用誰來調用
// string 變數就是我們要寫入的消息,它需要轉為Data // -1 和讀取消息時的意思一樣,表示不限定時間 // tag 為標記值,一般置為0 [newSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
6、讀取到 socket 的消息,在 readDataWithTimeout 後執行
主要用於對接收到消息的處理和將消息轉發給另一個接收的客戶端,這樣就起到兩個客戶端的通信,具體數據格式和邏輯根據個人需求自行處理。以下方法和readDataWithTimeout 方法配套執行,只要有 readDataWithTimeout 方法,就會有下麵的方法
// 參數1:伺服器的socket // 參數2:伺服器讀取的數據 // 參數3:標記 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
7、關閉伺服器
將伺服器的 socket 斷開連接後置為nil
#pragma mark - 關閉服務 - (IBAction)stopService:(NSButton *)sender { if (self.socket) { #warning 關閉 [self.socket disconnect]; self.socket = nil; [self addInfoString:@"關閉服務"]; } else { [self addInfoString:@"已經關閉,無需重覆"]; } }
8、監聽連接的斷開
當伺服器斷開連接後調用,主要用於處理socket存儲列表。
// 已經斷開連接時調用,監聽連接的斷開,並且處理socket存儲列表 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { // [self addInfoString:[NSString stringWithFormat:@"已經斷開連接 %@", err]]; [self addInfoString:[NSString stringWithFormat:@"已經斷開連接"]]; if ([self.clients allKeysForObject:sock].count > 0) { // 當客戶端斷開時,進行一些刪除socket的操作 [self.clients removeObjectForKey:[self.clients allKeysForObject:sock][0]]; NSLog(@"%@", self.clients); } else { // 當伺服器socket斷開時,處理客戶端socket列表 [self.clients removeAllObjects]; NSLog(@"%@", self.clients); } }
二、客戶端
在構建客戶器端的時候,需要導入第三方的類
#import "GCDAsyncSocket.h"
1、聲明和初始化客戶端socket(和伺服器端類似)
@interface ViewController () <GCDAsyncSocketDelegate> { // client端socket GCDAsyncSocket *_clientSocket; } @end _clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
2、連接伺服器
// 參數1:伺服器的IP地址 // 參數2:伺服器的埠號(伺服器綁定的埠號) // 參數3:錯誤信息 - (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr
3、連接到伺服器後執行的代理方法
主要用於從伺服器中讀取數據
// 連接到伺服器 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"連接到伺服器"); _serverSocket = sock; // 讀數據 [_serverSocket readDataWithTimeout:-1 tag:0]; }
4、讀到伺服器反饋的數據
方法和伺服器第6步的方法一樣,對伺服器反饋的數據進行處理和利用
5、讀寫消息的方法後伺服器端是一樣的,在這裡我就不再重覆介紹了,大家可以參照伺服器的讀寫消息的方法
三、下麵是自己學習的一個簡易版的Demo,有興趣的朋友可以下載看看
下載地址:https://github.com/AlonerOwl/Socket-