国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

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

2020-02-19 15:47:42
字體:
供稿:網(wǎng)友

使用socket可以實現(xiàn)QQ等即時信息的發(fā)送,客戶端和服務器需要建立很長的連接,以便在長連接的情況下發(fā)送消息,下面是武林技術(shù)頻道小編和大家講解iOS應用之使用AsyncSocket庫處理Socket通信的方法,希望對你有幫助!

特性

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

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

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

使用AsyncSocket的時候可以做一層封裝,根據(jù)需求提供幾個接口出來。比如:連接、斷開連接、發(fā)送消息等等。還有接受消息,接受到的消息可以通過通知、代理、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

//自己設(shè)定
#define HOST @"192.168.0.1"
#define PORT 8080

//設(shè)置連接超時
#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,實現(xiàn)startConnectSocket方法。這個時候要設(shè)置一下AsyncSocket的代理AsyncSocketDelegate。當長連接成功之后會調(diào)用:

?

?

?


- (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");

??? //通過定時器不斷發(fā)送消息,來檢測長連接
??? self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
??? [self.heartTimer fire];
}

// 心跳連接
-(void)checkLongConnectByServe{

??? // 向服務器發(fā)送固定可是的消息,來檢測長連接
??? NSString *longConnect = @"connect is here";
??? NSData?? *data? = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
??? [self.socket writeData:data withTimeout:1 tag:1];
}


在連接成功的回調(diào)方法里,啟動定時器,每隔2秒向服務器發(fā)送固定的消息來檢測長連接。(這個根據(jù)服務器的需要就可以了)

?

斷開連接

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斷開之后,會回調(diào)onSocket:willDisconnectWithError:方法,err.code == 57,這個時候設(shè)置self.socket.userData = SocketOfflineByWifiCut。

?

重新連接

socket斷開之后會回調(diào):

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回調(diào)方法里面,會根據(jù)self.socket.userData來判斷是否需要重新連接。

?

發(fā)送消息

LGSocketServe.h

?

// 發(fā)送消息
- (void)sendMessage:(id)message;
LGSocketServe.m

?

//設(shè)置寫入超時 -1 表示不會使用超時
#define WRITE_TIME_OUT -1

- (void)sendMessage:(id)message
{
??? //像服務器發(fā)送數(shù)據(jù)
??? NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];
??? [self.socket writeData:cmdData withTimeout:WRITE_TIME_OUT tag:1];
}

//發(fā)送消息成功之后回調(diào)
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{

}


發(fā)送消息成功之后會調(diào)用onSocket:didWriteDataWithTag:,在這個方法里可以進行讀取消息。

?

接受消息

LGSocketServe.m

?

//設(shè)置讀取超時 -1 表示不會使用超時
#define READ_TIME_OUT -1

?

#define MAX_BUFFER 1024

//發(fā)送消息成功之后回調(diào)
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
??? //讀取消息
??? [self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
}

//接受消息成功之后回調(diào)
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
??? //服務端返回消息數(shù)據(jù)量比較大時,可能分多次返回。所以在讀取消息的時候,設(shè)置MAX_BUFFER表示每次最多讀取多少,當data.length < MAX_BUFFER我們認為有可能是接受完一個完整的消息,然后才解析
??? if( data.length < MAX_BUFFER )
??? {
??????? //收到結(jié)果解析...
??????? 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:回調(diào)方法里面需要不斷讀取消息,因為數(shù)據(jù)量比較大的話,服務器會分多次返回。所以我們需要定義一個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出錯會回調(diào)onSocket:willDisconnectWithError:方法,可以通過unreadData來讀取未來得及讀取的buffer。

?

使用

導入#import “LGSocketServe.h”

?

?LGSocketServe *socketServe = [LGSocketServe sharedSocketServe];
//socket連接前先斷開連接以免之前socket連接沒有斷開導致閃退
[socketServe cutOffSocket];
socketServe.socket.userData = SocketOfflineByServer;
[socketServe startConnectSocket];

?

//發(fā)送消息 @"hello world"只是舉個列子,具體根據(jù)服務端的消息格式
[socketServe sendMessage:@"hello world"];

以上就是武林技術(shù)頻道小編收集的關(guān)于講解iOS應用之使用AsyncSocket庫處理Socket通信的方法!小編建議對這方面感興趣的可以抓住機會學習哦。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 微博| 田东县| 饶平县| 利川市| 台南市| 赣榆县| 庆云县| 恩平市| 池州市| 印江| 宁德市| 城固县| 封丘县| 陵水| 延安市| 苗栗市| 策勒县| 临洮县| 巴塘县| 民勤县| 宁陵县| 赣榆县| 噶尔县| 百色市| 铜山县| 班戈县| 辽阳县| 永昌县| 聂荣县| 新绛县| 双峰县| 青龙| 芒康县| 宣汉县| 库车县| 阳江市| 利川市| 买车| 铅山县| 通州区| 闻喜县|