iOS之Socket的使用-AsyncSocket

      網(wǎng)友投稿 875 2025-04-02

      iOS有原生的SOCKET,但AsyncSOCKET這個第三方庫,對socket的封裝比較好,本文就是基于AsyncSocket的使用介紹。


      環(huán)境

      下載AsyncSocket https://github.com/roustem/AsyncSocket類庫,將RunLoop文件夾下的AsyncSocket.h,AsyncSocket.m,AsyncUdpSocket.h,AsyncUdpSocket.m 文件拷貝到自己的project中。

      添加CFNetwork.framework, 再使用socket的文件頭:

      #import "AsyncSocket.h" #import "AsyncUdpSocket.h"

      1

      2

      3

      iOS之Socket的使用-AsyncSocket

      使用

      一、socket 連接

      即時通訊最大的特點就是實時性,基本感覺不到延時或是掉線,所以必須對socket的連接進(jìn)行監(jiān)視與檢測,在斷線時進(jìn)行重新連接,如果用戶退出登錄,要將socket手動關(guān)閉,否則對服務(wù)器會造成一定的負(fù)荷。

      一般來說,一個用戶只能有一個正在連接的socket,所以這個socket變量必須是全局的,可以使用單例或是AppDelegate進(jìn)行數(shù)據(jù)共享,本文使用單例。如果對一個已經(jīng)連接的socket對象再次進(jìn)行連接操作,會拋出異常(不可對已經(jīng)連接的 socket進(jìn)行連接)程序崩潰,所以在連接socket之前要對socket對象的連接狀態(tài)進(jìn)行判斷。

      使用socket進(jìn)行即時通訊還有一個必須的操作,即對服務(wù)器發(fā)送心跳包,每隔一段時間對服務(wù)器發(fā)送長連接指令(指令不唯一,由服務(wù)器端指定,包括使用socket發(fā)送消息,發(fā)送的數(shù)據(jù)和格式都是由服務(wù)器指定),如果沒有收到服務(wù)器的返回消息,AsyncSocket會得到失去連接的消息,我們可以 在失去連接的回調(diào)方法里進(jìn)行重新連接。

      先創(chuàng)建一個單例,命名為Singleton

      // Singleton.h #import "AsyncSocket.h" #define DEFINE_SHARED_INSTANCE_USING_BLOCK(block) static dispatch_once_t onceToken = 0; __strong static id sharedInstance = nil; dispatch_once(&onceToken, ^{ sharedInstance = block(); }); return sharedInstance; @interface Singleton : NSObject + (Singleton *)sharedInstance; @end //Singleton.m + (Singleton *)sharedInstance { static Singleton *sharedInstace = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstace = [[self alloc] init]; }); return sharedInstace; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      連接(長連接)

      在.h文件中聲明socket變量和方法,并聲明代理; 在.m中實現(xiàn),連接時host與port都是由服務(wù)器指定。

      //.h @property (nonatomic, strong) AsyncSocket *socket; // socket @property (nonatomic, copy ) NSString *socketHost; // socket的Host @property (nonatomic, assign) UInt16 socketPort; // socket的prot - (void)socketConnectHost; //socket連接 //.m - (void)socketConnectHost { self.socket = [[AsyncSocket alloc] initWithDelegate:self]; NSError *error = nil; [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error]; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      心跳

      心跳通過計時器來實現(xiàn):在singleton.h中聲明一個定時器;在singleton.m中實現(xiàn)連接成功回調(diào)方法,并在此方法中初始化定時器,發(fā)送心跳在后文向服務(wù)器發(fā)送數(shù)據(jù)時說明。

      //singleton.h @property (nonatomic, retain) NSTimer *connectTimer; // 計時器 //singleton.m #pragma mark - 連接成功回調(diào) - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port { NSLog(@"socket連接成功"); // 每隔30s像服務(wù)器發(fā)送心跳包 self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];// 在longConnectToSocket方法中進(jìn)行長連接需要向服務(wù)器發(fā)送的訊息 [self.connectTimer fire]; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      二、socket斷開連接與重連

      斷開連接

      失去連接有幾種情況,服務(wù)器斷開,用戶主動cut,還可能有如QQ其他設(shè)備登錄被掉線的情況,不管那種情況,都能收到socket回調(diào)方法返回訊息,如果是用戶退出登錄或是程序退出而需要手動cut,在cut前對socket的userData賦予一個值來標(biāo)記為用戶退出,這樣可以在收到斷開信息時判斷究竟是什么原因?qū)е碌牡艟€。

      在.h文件中聲明一個枚舉類型和斷開連接方法,并在.m中實現(xiàn)

      //.h enum{ SocketOfflineByServer,// 服務(wù)器掉線,默認(rèn)為0 SocketOfflineByUser, // 用戶主動cut }; - (void)cutOffSocket; // 斷開socket連接 //.m // 切斷socket - (void)cutOffSocket { self.socket.userData = SocketOfflineByUser;// 聲明是由用戶主動切斷 [self.connectTimer invalidate]; [self.socket disconnect]; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      重連

      //實現(xiàn)代理方法 - (void)onSocketDidDisconnect:(AsyncSocket *)sock { NSLog(@"sorry the connect is failure %ld",sock.userData); if (sock.userData == SocketOfflineByServer) { // 服務(wù)器掉線,重連 [self socketConnectHost]; } else if (sock.userData == SocketOfflineByUser) { // 如果由用戶斷開,不進(jìn)行重連 return; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      三、socket發(fā)送與接收數(shù)據(jù)

      發(fā)送數(shù)據(jù)

      實現(xiàn)心跳連接未完成的方法

      // 心跳連接 - (void)longConnectToSocket { // 根據(jù)服務(wù)器要求發(fā)送固定格式的數(shù)據(jù),假設(shè)為指令@"longConnect",但是一般不會是這么簡單的指令 NSString *longConnect = @"longConnect"; NSData *dataStream = [longConnect dataUsingEncoding:NSUTF8StringEncoding]; [self.socket writeData:dataStream withTimeout:1 tag:1]; }

      1

      2

      3

      4

      5

      6

      7

      socket發(fā)送數(shù)據(jù)是以棧的形式存放,所有數(shù)據(jù)放在一個棧中,存取時會出現(xiàn)粘包的現(xiàn)象,所以很多時候服務(wù)器在收發(fā)數(shù)據(jù)時是以先發(fā)送內(nèi)容字節(jié)長度, 再發(fā)送內(nèi)容的形式,得到數(shù)據(jù)時也是先得到一個長度,再根據(jù)這個長度在棧中讀取這個長度的字節(jié)流,如果是這種情況,發(fā)送數(shù)據(jù)時只需在發(fā)送內(nèi)容前發(fā)送一個長 度,發(fā)送方法與發(fā)送內(nèi)容一樣,假設(shè)長度為8

      NSData *dataStream = [@8 dataUsingEncoding:NSUTF8StringEncoding]; [self.socket writeData:dataStream withTimeout:1 tag:1];

      1

      2

      接收數(shù)據(jù)

      //為了能時刻接收到socket的消息,在長連接方法中進(jìn)行讀取數(shù)據(jù) [self.socket readDataWithTimeout:30 tag:0]; //如果得到數(shù)據(jù),會調(diào)用回調(diào)方法 - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { // 對得到的data值進(jìn)行解析與轉(zhuǎn)換即可 [self.socket readDataWithTimeout:30 tag:0]; }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      四、簡單使用說明

      在用戶登錄后的第一個界面進(jìn)行socket的初始化連接操作,在得到數(shù)據(jù)后,將所需要顯示的數(shù)據(jù)放在singleton中,對變量進(jìn)行監(jiān)聽后做出相應(yīng)的操作即可。

      [Singleton sharedInstance].socketHost = @"192.186.100.21";// host設(shè)定 [Singleton sharedInstance].socketPort = 10045;// port設(shè)定 // 在連接前先進(jìn)行手動斷開 [Singleton sharedInstance].socket.userData = SocketOfflineByUser; [[Singleton sharedInstance] cutOffSocket]; // 確保斷開后再連,如果對一個正處于連接狀態(tài)的socket進(jìn)行連接,會出現(xiàn)崩潰 [Singleton sharedInstance].socket.userData = SocketOfflineByServer; [[Singleton sharedInstance] socketConnectHost];

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      iOS Socket編程

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:excel2016怎么開啟輸入時提示函數(shù)參數(shù)功能?
      下一篇:如何在wps中保存圖片如何在word中批量保存圖片
      相關(guān)文章
      亚洲一区二区三区免费在线观看| 亚洲视频一区调教| 亚洲国产精品yw在线观看| 亚洲男人都懂得羞羞网站| 好看的电影网站亚洲一区| 亚洲人成网77777亚洲色| 亚洲伊人成无码综合网 | 亚洲国产一区视频| 亚洲?V乱码久久精品蜜桃 | 亚洲免费一区二区| 亚洲中文字幕丝袜制服一区| 亚洲日本一区二区三区在线不卡| 亚洲福利在线播放| 亚洲人成网站色在线入口| 亚洲欧洲自拍拍偷精品 美利坚| 亚洲国产精品人人做人人爱| 亚洲精品国产精品乱码不卞 | 亚洲成人免费在线观看| 亚洲男女一区二区三区| 亚洲国产情侣一区二区三区| 亚洲一区中文字幕在线观看| 亚洲三级高清免费| 亚洲色成人网站WWW永久四虎 | 亚洲av日韩aⅴ无码色老头| 欧美日韩亚洲精品| 亚洲阿v天堂在线2017免费| 亚洲天堂在线视频| 亚洲日韩国产精品第一页一区| 国产精品亚洲аv无码播放| 久久久无码精品亚洲日韩蜜臀浪潮| 久久99亚洲网美利坚合众国| 亚洲剧场午夜在线观看| 亚洲色大成网站www永久网站| 九九精品国产亚洲AV日韩| 亚洲视频在线精品| 亚洲va无码手机在线电影| 亚洲黄色高清视频| 亚洲人成网站色在线观看| 校园亚洲春色另类小说合集| 久久亚洲AV无码西西人体| 亚洲国产精品福利片在线观看|