zoukankan      html  css  js  c++  java
  • 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"];
  • 相关阅读:
    祝大家光棍节快乐!
    [Spring] Oracle TopLink O/R Mapping integrates Spring.
    VS2005 vs Eclipse, functions i expected.
    [English] Adverb for link (Chinese)
    有几个Gmail的Invitation
    Experience online service of MS small business (bCentral)
    多态(Polymorphism)
    Check your site and build meta tags for search engines
    关于怎样用javascript判断网页上我们想要必须选择的复选框至少选择一个的问题
    关于在VS2010中学习c++的MFC
  • 原文地址:https://www.cnblogs.com/iOSDeng/p/5072903.html
Copyright © 2011-2022 走看看