亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS應用中使用AsyncSocket庫處理Socket通信的用法講解

2020-07-26 03:20:51
字體:
來源:轉載
供稿:網友

用socket可以實現像QQ那樣發送即時消息的功能??蛻舳撕头斩诵枰㈤L連接,在長連接的情況下,發送消息。客戶端可以發送心跳包來檢測長連接。

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

特性

AsyncSocket類是支持TCP的。
AsyncUdpSocket是支持UDP的。
AsyncSocket是封裝了CFSocket和CFSteam的TCP/IP socket網絡庫。它提供了異步操作,本地cocoa類的基于delegate的完整支持。主要有以下特性:

  • 隊列的非阻塞的讀和寫,而且可選超時。你可以調用它讀取和寫入,它會當完成后告知你。
  • 自動的socket接收。如果你調用它接收連接,它將為每個連接啟動新的實例,當然,也可以立即關閉這些連接。
  • 委托(delegate)支持。錯誤、連接、接收、完整的讀取、完整的寫入、進度以及斷開連接,都可以通過委托模式調用。
  • 基于run loop的,而不是線程的。雖然可以在主線程或者工作線程中使用它,但你不需要這樣做。它異步的調用委托方法,使用NSRunLoop。委托方法包括socket的參數,可讓你在多個實例中區分。
  • 自包含在一個類中。你無需操作流或者socket,這個類幫你做了全部。
  • 支持基于IPV4和IPV6的TCP流。

AsyncUdpSocket是UDP/IP socket網絡庫,包裝自CFSocket。它的工作很像TCP版本,只不過是用于處理UDP的。它包括基于非阻塞隊列的發送接收操作,完整的委托支持,基于runloop,自包含的類,以及支持IPV4和IPV6。

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

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

定義單列類:LGSocketServe

LGSocketServe.h

復制代碼 代碼如下:

//
//  LGSocketServe.h
//  AsyncSocketDemo
//

#import <Foundation/Foundation.h>
#import "AsyncSocket.h"

@interface LGSocketServe : NSObject<AsyncSocketDelegate>

+ (LGSocketServe *)sharedSocketServe;


@end


LGSocketServe.m
復制代碼 代碼如下:

//
//  LGSocketServe.m
//  AsyncSocketDemo
//

#import "LGSocketServe.h"

@implementation LGSocketServe


static 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"];

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧亚精品中文字幕| 成人h猎奇视频网站| 欧美性生活大片免费观看网址| 色综合91久久精品中文字幕| 欧美黄色片免费观看| 91系列在线观看| 亚洲一区www| 欧美另类69精品久久久久9999| 一区二区三区高清国产| 7777精品久久久久久| 国产精品人成电影在线观看| 高清日韩电视剧大全免费播放在线观看| 国产精品日韩一区| 蜜臀久久99精品久久久无需会员| 最近2019年好看中文字幕视频| 国产成人亚洲综合青青| 中文字幕成人在线| 日本久久亚洲电影| 欧美在线一级视频| 亚洲综合一区二区不卡| 久久99精品久久久久久噜噜| 亚洲精品网站在线播放gif| 91免费观看网站| 国产日韩在线看片| 黄色精品一区二区| 91精品国产成人www| 伊人久久久久久久久久| 久久99久久99精品免观看粉嫩| 久久久精品一区二区| 欧美日韩国产一区中文午夜| 欧美国产在线视频| 夜夜嗨av一区二区三区四区| 亚洲自拍偷拍区| 欧美精品一区在线播放| 久久精品视频亚洲| 91精品国产91久久久久久| 日本午夜人人精品| 亚洲国产精品久久| 亚洲欧洲美洲在线综合| 韩国美女主播一区| 国产精品福利片| 亚洲电影免费观看高清完整版在线观看| 日韩av日韩在线观看| 福利微拍一区二区| 国产精品免费小视频| 欧美日本高清一区| 日韩欧美成人免费视频| 欧美性少妇18aaaa视频| 日韩欧美在线免费观看| 亚洲成人网在线观看| 欧美激情在线观看| 欧美中文字幕视频| 亚洲欧美在线一区二区| 日本欧美精品在线| 亚洲欧美日韩精品| 久久综合亚洲社区| 国产99久久精品一区二区| 另类视频在线观看| 97涩涩爰在线观看亚洲| 98午夜经典影视| 热草久综合在线| 欧美中文字幕在线视频| 国产日韩欧美在线| 国产在线精品一区免费香蕉| 国产精品mp4| 亚洲视频精品在线| 国产精自产拍久久久久久| 日本精品免费观看| 最近2019年日本中文免费字幕| 欧美成人免费观看| 久久久精品国产一区二区| 国产精品三级久久久久久电影| 国语自产精品视频在线看抢先版图片| 亚洲欧美日韩精品久久亚洲区| 欧美日本黄视频| 美女av一区二区三区| 这里精品视频免费| 国产日韩欧美自拍| 日韩综合视频在线观看| 91视频国产精品| 亚洲aaa激情| 国产一区二区av| 久久国产精品偷| 国产精品福利在线观看| 懂色av影视一区二区三区| 国产精品福利久久久| 精品日韩美女的视频高清| 国产欧美日韩精品丝袜高跟鞋| 成人免费网站在线看| 欧美成人性色生活仑片| 91精品久久久久久| 久久男人资源视频| 精品中文字幕在线观看| 日韩精品高清视频| 成人网欧美在线视频| 91精品国产777在线观看| 国产在线视频一区| 91九色视频导航| 亚洲黄色www| 视频一区视频二区国产精品| 国产精品永久免费观看| 色综合影院在线| 久色乳综合思思在线视频| 亚洲自拍中文字幕| 91亚洲国产精品| 亚洲国产高潮在线观看| 91干在线观看| 成人性生交大片免费看视频直播| 黑人巨大精品欧美一区二区一视频| 国产精品美女免费看| 午夜伦理精品一区| 国产精品美乳一区二区免费| 久久久免费观看| 国产精品∨欧美精品v日韩精品| 国产不卡av在线免费观看| 午夜精品久久久久久99热| 九九视频这里只有精品| 日韩成人激情视频| 精品久久久久久久久久久久久久| 中文字幕亚洲精品| 久久韩国免费视频| 国产免费一区二区三区在线能观看| 成人乱人伦精品视频在线观看| 日韩av在线免费| 51精品在线观看| 日韩免费视频在线观看| 91精品久久久久久久久久另类| 欧美极品美女视频网站在线观看免费| 精品国产精品三级精品av网址| 黄色成人在线免费| 91禁国产网站| 中文字幕在线亚洲| 欧美成人三级视频网站| 一区二区三区久久精品| 欧美一级高清免费| 亚洲精品成a人在线观看| 日本久久久久久| 欧美亚洲在线播放| 亚洲bt欧美bt日本bt| 亚洲第一区第一页| 欧美影院成年免费版| 亚洲香蕉成视频在线观看| 欧美黑人视频一区| 国产精品久久精品| 亚洲色图25p| 欧美日韩xxx| 欧美黄色www| 色噜噜亚洲精品中文字幕| 久久久久久久网站| 国产91在线视频| 日韩电影免费观看在线观看| 日韩在线播放一区| 欧美午夜宅男影院在线观看| 久久成人综合视频| 亚洲伊人一本大道中文字幕| 亚洲国产精品99久久| 国内外成人免费激情在线视频| 操日韩av在线电影| 久久亚洲一区二区三区四区五区高| 亚洲人成亚洲人成在线观看| 97碰在线观看| 狠狠色噜噜狠狠狠狠97| 97久久久免费福利网址| 在线观看欧美成人|