一夏哭、簡(jiǎn)介
CocoaAsyncSocket是谷歌的開發(fā)者,基于BSD-Socket寫的一個(gè)IM框架,可在github下載 乡摹,它給Mac和iOS提供了易于使用的再层、強(qiáng)大的異步套接字庫(kù),向上封裝出簡(jiǎn)單易用OC接口秽五。省去了我們面向Socket以及數(shù)據(jù)流Stream等繁瑣復(fù)雜的編程孽查。其結(jié)構(gòu)框架簡(jiǎn)介示意圖如下:
整個(gè)庫(kù)就這么兩個(gè)類,一個(gè)基于TCP坦喘,一個(gè)基于UDP盲再。其中基于TCP的GCDAsyncSocket,大概8000多行代碼瓣铣。而GCDAsyncUdpSocket稍微少一點(diǎn)答朋,也有5000多行。
1.GCDAsyncSocket.
用GCD搭建的基于TCP/IP協(xié)議的socket網(wǎng)絡(luò)庫(kù)
GCDAsyncSocket is a TCP/IP socket networking library built atop Grand Central Dispatch. -- 來(lái)源于CocoaAsyncSocket.
2.GCDAsyncUdpSocket
用GCD搭建的基于UDP/IP協(xié)議的socket網(wǎng)絡(luò)庫(kù).
GCDAsyncUdpSocket is a UDP/IP socket networking library built atop Grand Central Dispatch..--來(lái)源于CocoaAsyncSocket.
二棠笑、客戶端
因?yàn)?大部分項(xiàng)目已經(jīng)有服務(wù)端socket,所以,先講解客戶端創(chuàng)建過(guò)程.
步驟:
1.繼承GCDAsyncSocketDelegate協(xié)議.
2.聲明屬性
// 客戶端socket
@property (strong, nonatomic) GCDAsyncSocket *clientSocket梦碗;
3.創(chuàng)建socket并指定代理對(duì)象為self,代理隊(duì)列必須為主隊(duì)列.
self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
4.連接指定主機(jī)的對(duì)應(yīng)端口.
NSError *error = nil;
self.connected = [self.clientSocket connectToHost:self.addressTF.text onPort:[self.portTF.text integerValue] viaInterface:nil withTimeout:-1 error:&error];
5.成功連接主機(jī)對(duì)應(yīng)端口號(hào).
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
// NSLog(@"連接主機(jī)對(duì)應(yīng)端口%@", sock);
[self showMessageWithStr:@"鏈接成功"];
[self showMessageWithStr:[NSString stringWithFormat:@"服務(wù)器IP: %@-------端口: %d", host,port]];
// 連接成功開啟定時(shí)器
[self addTimer];
// 連接后,可讀取服務(wù)端的數(shù)據(jù)
[self.clientSocket readDataWithTimeout:- 1 tag:0];
self.connected = YES;
}
IP---其中的IP服務(wù)器的IP地址
6、向服務(wù)器發(fā)送數(shù)據(jù)
向服務(wù)器發(fā)送數(shù)據(jù)主要通過(guò)- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag 來(lái)向后臺(tái)發(fā)送數(shù)據(jù)的
- (IBAction)sendMessageAction:(id)sender
{
NSData *data = [self.messageTextF.text dataUsingEncoding:NSUTF8StringEncoding];
// withTimeout 0 : 等待時(shí)間
// tag : 消息標(biāo)記
[self.clientSocket writeData:data withTimeout:0 tag:0];
}
7蓖救、讀取數(shù)據(jù)
/**
讀取數(shù)據(jù)
@param sock 客戶端socket
@param data 讀取到的數(shù)據(jù)
@param tag 本次讀取的標(biāo)記
*/
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *text = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
[self showMessageWithStr:text];
// 讀取到服務(wù)端數(shù)據(jù)值后,能再次讀取
[self.clientSocket readDataWithTimeout:- 1 tag:0];
}
主要通過(guò)方法-(void) readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag來(lái)進(jìn)行的
8洪规、斷開連接
/**
客戶端socket斷開
@param sock 客戶端socket
@param err 錯(cuò)誤描述
*/
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
[self showMessageWithStr:@"斷開連接"];
self.clientSocket.delegate = nil;
self.clientSocket = nil;
self.connected = NO;
[self.connectTimer invalidate];
}
9、建立心跳
心跳連接中發(fā)送給服務(wù)端的數(shù)據(jù)只是作為測(cè)試代碼,根據(jù)你們公司需求,或者和后臺(tái)商定好心跳包的數(shù)據(jù)以及發(fā)送心跳的時(shí)間間隔.客戶端發(fā)送心跳包,服務(wù)端也需要有對(duì)應(yīng)的心跳檢測(cè),以此檢測(cè)客戶端是否在線.
// 計(jì)時(shí)器
@property (nonatomic, strong) NSTimer *connectTimer;
// 添加定時(shí)器
- (void)addTimer
{
// 長(zhǎng)連接定時(shí)器
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
// 把定時(shí)器添加到當(dāng)前運(yùn)行循環(huán),并且調(diào)為通用模式
[[NSRunLoop currentRunLoop] addTimer:self.connectTimer forMode:NSRunLoopCommonModes];
}
// 心跳連接
- (void)longConnectToSocket
{
// 發(fā)送固定格式的數(shù)據(jù),指令@"longConnect"
float version = [[UIDevice currentDevice] systemVersion].floatValue;
NSString *longConnect = [NSString stringWithFormat:@"123%f",version];
NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
[self.clientSocket writeData:data withTimeout:- 1 tag:0];
}