• CocoaAsyncSocket框架的简单封装


    在iOS开发中使用socket(CFNetwork),一般都是用第三方库AsyncSocket。

    参考博客:http://my.oschina.net/worldligang/blog/396881?fromerr=WRR1ZAie

    CocoaAsyncSocket的git下载地址:https://github.com/robbiehanson/CocoaAsyncSocket

    下载CocoaAsyncSocket的文件,导入runloop中的AsyncSocket.h和AsyncSocket.m文件。

    以下就是封装的CocoaAsyncSocket工具类DLSocketServe。

     1 //
     2 //  DLSocketServe.h
     3 //  AsnycSocketDemo
     4 //
     5 //  Created by wiseman on 15/12/23.
     6 //  Copyright (c) 2015年 wiseman. All rights reserved.
     7 //
     8 #import <Foundation/Foundation.h>
     9 #import "AsyncSocket.h"
    10 
    11 enum{
    12     SocketOfflineByServer,      //服务器掉线
    13     SocketOfflineByUser,        //用户断开
    14     SocketOfflineByWifiCut,     //wifi 断开
    15 };
    16 
    17 @interface DLSocketServe : NSObject<AsyncSocketDelegate>
    18 
    19 @property (strong,nonatomic) AsyncSocket * socket;
    20 
    21 @property (retain,nonatomic) NSTimer *heartTimer; //心跳计时器
    22 
    23 +(DLSocketServe *)sharedSocketServe;
    24 
    25 //socket连接
    26 -(void)startConnetSocket;
    27 
    28 //断开socket连接
    29 -(void)cutOffSocket;
    30 
    31 //发送消息
    32 -(void)sendMessage:(id)message;
    33 @end
      1 //
      2 //  DLSocketServe.m
      3 //  AsnycSocketDemo
      4 //
      5 //  Created by wiseman on 15/12/23.
      6 //  Copyright (c) 2015年 wiseman. All rights reserved.
      7 //
      8 
      9 
     10 #define HOST @"192.168.1.1"
     11 #define PORT 8080
     12 
     13 #define TIME_OUT 20
     14 
     15 //设置读取超时 -1 表示不会使用超时
     16 #define READ_TIME_OUT -1
     17 
     18 //设置写入超时 -1表示不会使用超时
     19 #define WRITW_TIME_OUT -1
     20 #define MAX_BUFFER 1024
     21 
     22 
     23 #import "DLSocketServe.h"
     24 
     25 @implementation DLSocketServe
     26 
     27 static DLSocketServe *socketServe = nil;
     28 
     29 //创建一个单例方法
     30 +(DLSocketServe *)sharedSocketServe{
     31     //@synchronized 的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。 一般在公用变量的时候使用,如单例模式或者操作类的static变量中使用。
     32     @synchronized(self){
     33         if(socketServe == nil) {
     34             socketServe = [[[self class] alloc] init];
     35         }
     36     }
     37     return socketServe;
     38 }
     39 
     40 +(instancetype)allocWithZone:(struct _NSZone *)zone{
     41     @synchronized(self){
     42         if (socketServe == nil) {
     43             socketServe = [super allocWithZone:zone];
     44             return socketServe;
     45         }
     46     }
     47     return nil;
     48 }
     49 
     50 -(void)startConnetSocket{
     51     self.socket = [[AsyncSocket alloc]initWithDelegate:self];
     52     [self.socket setRunLoopModes:@[NSRunLoopCommonModes]];
     53     if (![self SocketOpen:HOST port:PORT]) {
     54         
     55     }
     56 }
     57 
     58 -(NSInteger)SocketOpen:(NSString *)addr port:(NSInteger)port{
     59     if (!([self.socket isConnected])) {
     60         NSError *error = nil;
     61         [self.socket connectToHost:addr onPort:port withTimeout:TIME_OUT error:&error];
     62     }
     63     return 0;
     64 }
     65 
     66 
     67 //发送消息
     68 -(void)sendMessage:(id)message{
     69     //向服务器发送数据
     70     NSData *cmdData = [message dataUsingEncoding:NSUTF8StringEncoding];
     71     [self.socket writeData:cmdData withTimeout:WRITW_TIME_OUT tag:1];
     72 }
     73 
     74 #pragma mark - AsyncSocket代理
     75 -(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
     76     NSLog(@"这是异步返回的连接成功");
     77     
     78     //通过定时器不断的发送消息,来检测长连接
     79     self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES];
     80     [self.heartTimer fire];
     81 }
     82 
     83 //心跳连接
     84 -(void)checkLongConnectByServe{
     85     //向服务器发送固定的消息,来检测长连接
     86     NSString *longConnect = @"connect is here";
     87     NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding];
     88     [self.socket writeData:data withTimeout:0 tag:0];
     89 }
     90 
     91 //断开连接
     92 //1.用户手动断开连接
     93 -(void)cutOffSocket{
     94     self.socket.userData = SocketOfflineByUser;
     95     //cutOffSocket 是用户断开连接之后,不在尝试重新连接
     96     [self.socket disconnect];
     97 }
     98 
     99 //2.wifi断开,socket断开连接
    100 -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{
    101     
    102     NSData * unreadData = [sock unreadData]; // ** This gets the current buffer
    103     if(unreadData.length > 0) {
    104 //        socket出错会回调onSocket:willDisconnectWithError:方法,可以通过unreadData来读取未来得及读取的buffer。
    105         [self onSocket:sock didReadData:unreadData withTag:0];
    106         
    107     } else {
    108         
    109         //wifi断开之后,会回调onSocket:willDisconnectWithError:方法,err.code == 57,这个时候设置self.socket.userData = SocketOfflineByWifiCut
    110         NSLog(@" willDisconnectWithError %ld   err = %@",sock.userData,[err description]);
    111         if (err.code == 57) {
    112             self.socket.userData = SocketOfflineByWifiCut;
    113         }
    114 
    115     }
    116     
    117 }
    118 
    119 //重新连接
    120 //socket断开之后会回调  在onSocketDidDisconnect回调方法里面,会根据self.socket.userData来判断是否需要重新连接。
    121 -(void)onSocketDidDisconnect:(AsyncSocket *)sock{
    122     NSLog(@"%ld",sock.userData);
    123     if (sock.userData == SocketOfflineByServer) {
    124         //服务器掉线,重连
    125         [self startConnetSocket];
    126     }
    127     else if (sock.userData == SocketOfflineByUser){
    128         //如果由用户断开,不进行重连
    129         return;
    130     }
    131     else if (sock.userData == SocketOfflineByWifiCut){
    132         //wifi断开,不进行重连
    133         return;
    134     }
    135 }
    136 
    137 
    138 //发送消息成功之后回调
    139 -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{
    140     //发送消息成功之后会调用onSocket:didWriteDataWithTag:,在这个方法里可以进行读取消息。
    141     //读取消息
    142     [self.socket readDataWithTimeout:-1 buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
    143 }
    144 
    145 //接受消息成功之后回调
    146 -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    147     //服务端返回消息数据量比较大时,可能分多次返回。所以在读取消息的时候,设置MAX_BUFFER表示每次最多读取多少,当data.length < MAX_BUFFER我们认为有可能是接受完一个完整的消息,然后才解析
    148     
    149     if (data.length < MAX_BUFFER) {
    150         //收到结果解析
    151         NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
    152         NSLog(@"%@",dic);
    153         //解析出来的消息,可以通过通知,代理,block等传递出去
    154         
    155     }
    156     
    157     [self.socket readDataWithTimeout:READ_TIME_OUT buffer:nil bufferOffset:0 maxLength:MAX_BUFFER tag:0];
    158     
    159 }
    160 
    161 - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
    162 {
    163     NSLog(@"didAcceptNewSocket");
    164 }
    165 
    166 
    167 
    168 @end

    封装好之后,使用:

    导入:#import "DLSocketServe.h"

    1 DLSocketServe *socketServe = [DLSocketServe sharedSocketServe];
    2 //socket连接前先断开连接以免之前socket连接没有断开导致闪退
    3 [socketServe cutOffSocket];
    4 socketServe.socket.userData = SocketOfflineByServer;
    5 [socketServe startConnectSocket];
    6 
    7 //发送消息 @"hahaha"只是举个列子,具体根据服务端的消息格式
    8 [socketServe sendMessage:@"hahaha"];
  • 相关阅读:
    LeetCode 485. Max Consecutive Ones
    LeetCode 367. Valid Perfect Square
    LeetCode 375. Guess Number Higher or Lower II
    LeetCode 374. Guess Number Higher or Lower
    LeetCode Word Pattern II
    LeetCode Arranging Coins
    LeetCode 422. Valid Word Square
    Session 共享
    java NIO
    非阻塞IO
  • 原文地址:https://www.cnblogs.com/iOSDeng/p/5072903.html
Copyright © 2020-2023  润新知