iOS開發之AsyncSocket使用教程

來源:互聯網
上載者:User

標籤:iosdevtip   socket   asyncsocket   git   

AsyncSocketDemo: AsyncSocketDemo


用socket可以實現像QQ那樣傳送立即訊息的功能。用戶端和服務端需要建立長串連,在長串連的情況下,發送訊息。用戶端可以發送心跳包來檢測長串連。

在iOS開發中使用socket,一般都是用第三方庫AsyncSocket,不得不承認這個庫確實很強大。CocoaAsyncSocket

使用AsyncSocket的時候可以做一層封裝,根據需求提供幾個介面出來。比如:串連、中斷連線、發送訊息等等。還有接受訊息,接受到的訊息可以通過通知、代理、block等傳出去。

簡單介紹一下對AsyncSocket使用.一般來說,一個使用者只需要建立一個socket長串連,所以可以用單例類方便使用。

定義單列類:LGSocketServe

LGSocketServe.h

////  LGSocketServe.h//  AsyncSocketDemo////  Created by ligang on 15/4/3.//  Copyright (c) 2015年 ligang. All rights reserved.//#import <Foundation/Foundation.h>#import "AsyncSocket.h"@interface LGSocketServe : NSObject<AsyncSocketDelegate>+ (LGSocketServe *)sharedSocketServe;@end

LGSocketServe.m


////  LGSocketServe.m//  AsyncSocketDemo////  Created by ligang on 15/4/3.//  Copyright (c) 2015年 ligang. All rights reserved.//#import "LGSocketServe.h"@implementation LGSocketServestatic LGSocketServe *socketServe = nil;#pragma mark public static methods+ (LGSocketServe *)sharedSocketServe {    @synchronized(self) {        if(socketServe == nil) {            socketServe = [[[self class] alloc] init];        }    }    return socketServe;}+(id)allocWithZone:(NSZone *)zone{    @synchronized(self)    {        if (socketServe == nil)        {            socketServe = [super allocWithZone:zone];            return socketServe;        }    }    return nil;}   @end

建立socket長串連

LGSocketServe.h

@property (nonatomic, strong) AsyncSocket         *socket;       // socket//  socket串連- (void)startConnectSocket;

LGSocketServe.m

//自己設定#define HOST @"192.168.0.1"#define PORT 8080//設定連線逾時#define TIME_OUT 20- (void)startConnectSocket{    self.socket = [[AsyncSocket alloc] initWithDelegate:self];    [self.socket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];    if ( ![self SocketOpen:HOST port:PORT] )    {    }}- (NSInteger)SocketOpen:(NSString*)addr port:(NSInteger)port{    if (![self.socket isConnected])    {        NSError *error = nil;        [self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error];    }    return 0;}

宏定義一下HOST、PORT、TIME_OUT,實現startConnectSocket方法。這個時候要設定一下AsyncSocket的代理AsyncSocketDelegate。當長串連成功之後會調用:


- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{    //這是非同步返回的串連成功,    NSLog(@"didConnectToHost");}

心跳

LGSocketServe.h

@property (nonatomic, retain) NSTimer             *heartTimer;   // 心跳計時器

LGSocketServe.m

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{    //這是非同步返回的串連成功,    NSLog(@"didConnectToHost");    //通過定時器不斷髮送訊息,來檢測長串連    self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];    [self.heartTimer fire];}// 心跳串連-(void)checkLongConnectByServe{    // 向伺服器發送固定可是的訊息,來檢測長串連    NSString *longConnect = @"connect is here";    NSData   *data  = [longConnect dataUsingEncoding:NSUTF8StringEncoding];    [self.socket writeData:data withTimeout:1 tag:1];}

在串連成功的回調方法裡,啟動定時器,每隔2秒向伺服器發送固定的訊息來檢測長串連。(這個根據伺服器的需要就可以了)

中斷連線

1,使用者手動中斷連線

LGSocketServe.h


// 斷開socket串連-(void)cutOffSocket;

LGSocketServe.m

-(void)cutOffSocket{    self.socket.userData = SocketOfflineByUser;    [self.socket disconnect];}

cutOffSocket是使用者中斷連線之後,不在嘗試重新串連。

2,wifi斷開,socket中斷連線

LGSocketServe.m

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{    NSLog(@" willDisconnectWithError %ld   err = %@",sock.userData,[err description]);    if (err.code == 57) {        self.socket.userData = SocketOfflineByWifiCut;    }}

wifi斷開之後,會回調onSocket:willDisconnectWithError:方法,err.code == 57,這個時候設定self.socket.userData = SocketOfflineByWifiCut。

重新串連

socket斷開之後會回調:

LGSocketServe.m

- (void)onSocketDidDisconnect:(AsyncSocket *)sock{    NSLog(@"7878 sorry the connect is failure %ld",sock.userData);    if (sock.userData == SocketOfflineByServer) {        // 伺服器掉線,重連        [self startConnectSocket];    }    else if (sock.userData == SocketOfflineByUser) {        // 如果由使用者斷開,不進行重連        return;    }else if (sock.userData == SocketOfflineByWifiCut) {        // wifi斷開,不進行重連        return;    }}

在onSocketDidDisconnect回調方法裡面,會根據self.socket.userData來判斷是否需要重新串連。

發送訊息

LGSocketServe.h


// 發送訊息- (void)sendMessage:(id)message;


LGSocketServe.m

//設定寫入逾時 -1 表示不會使用逾時#define WRITE_TIME_OUT -1- (void)sendMessage:(id)message{    //像伺服器發送資料    NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];    [self.socket writeData:cmdData withTimeout:WRITE_TIME_OUT tag:1];}//發送訊息成功之後回調- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{}

發送訊息成功之後會調用onSocket:didWriteDataWithTag:,在這個方法裡可以進行讀取訊息。

接受訊息

LGSocketServe.m

//設定讀取逾時 -1 表示不會使用逾時#define READ_TIME_OUT -1#define MAX_BUFFER 1024//發送訊息成功之後回調- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{    //讀取訊息    [self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];}//接受訊息成功之後回調- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{    //服務端返回訊息資料量比較大時,可能分多次返回。所以在讀取訊息的時候,設定MAX_BUFFER表示每次最多讀取多少,當data.length < MAX_BUFFER我們認為有可能是接受完一個完整的訊息,然後才解析    if( data.length < MAX_BUFFER )    {        //收到結果解析...        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];        NSLog(@"%@",dic);        //解析出來的訊息,可以通過通知、代理、block等傳出去    }    [self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];

接受訊息後去解析,然後可以通過通知、代理、block等傳出去。在onSocket:didReadData:withTag:回調方法裡面需要不斷讀取訊息,因為資料量比較大的話,伺服器會分多次返回。所以我們需要定義一個MAX_BUFFER的宏,表示每次最多讀取多少。當data.length < MAX_BUFFER我們認為有可能是接受完一個完整的訊息,然後才解析。

出錯處理

LGSocketServe.m

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{    NSData * unreadData = [sock unreadData]; // ** This gets the current buffer    if(unreadData.length > 0) {        [self onSocket:sock didReadData:unreadData withTag:0]; // ** Return as much data that could be collected    } else {        NSLog(@" willDisconnectWithError %ld   err = %@",sock.userData,[err description]);        if (err.code == 57) {            self.socket.userData = SocketOfflineByWifiCut;        }    }}

socket出錯會回調onSocket:willDisconnectWithError:方法,可以通過unreadData來讀取未來得及讀取的buffer。

使用

匯入#import “LGSocketServe.h”

 LGSocketServe *socketServe = [LGSocketServe sharedSocketServe];//socket串連前先中斷連線以免之前socket串連沒有斷開導致閃退[socketServe cutOffSocket];socketServe.socket.userData = SocketOfflineByServer;[socketServe startConnectSocket];//發送訊息 @"hello world"只是舉個列子,具體根據服務端的訊息格式[socketServe sendMessage:@"hello world"];

以上是AsyncSocket的簡單使用,在實際開發過程中依然會碰到很多問題,歡迎加我的公眾號iOS開發:iOSDevTip,一起討論AsyncSocket中遇到的問題。

AsyncSocketDemo: AsyncSocketDemo


iOS開發之AsyncSocket使用教程

聯繫我們

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