美文网首页iphone X ios 11iOS知识收集ios初级篇
iOS 基于GCDAsyncSocket快速开发Socket通信

iOS 基于GCDAsyncSocket快速开发Socket通信

作者: 宫城_ | 来源:发表于2016-01-17 13:02 被阅读22289次

    原文地址:iOS 基于GCDAsyncSocket快速开发Socket通信 · 宫城

    以及Socket重构设计:iOS Socket重构设计

    看到留言区很多人都在使用中遇到问题,为了方便大家一起学习交流,我建了一个微信群,可以通过关注我的公众号,点击菜单栏【加群交流】,大家一起来交流


    GCDAsyncSocket是CocoaAsyncSocket第三方库中的其中一个类,本文介绍的就是基于这一个类来做快速的socket通信开发

    这个是我对GCDAsyncSocket的一层封装调用,它包含了建连、断开、重连、心跳、自定义请求

    GitHub - Yuzeyang/GCDAsyncSocketManager

    好用的话,请帮我star、fork一下喔~


    首先,介绍一下CocoaAsyncSocket第三方库的用途

    CocoaAsyncSocket provides easy-to-use and powerful asynchronous socket libraries for Mac and iOS. 

    翻译成:

    CocoaAsyncSocket为Mac和iOS提供了易于使用且强大的异步通信库

    在Podfile文件中,只要加上这句话就可以使用了

    pod'CocoaAsyncSocket', '7.4.1'


    简单的Socket通信包括了建连、断开连接、发送socket业务请求、重连这四个基本功能

    下面,我就按照这个四个基本功能来讲一下,怎么来使用CocoaAsyncSocket中GCDAsyncSocket这个类来开发Socket通信

    首先,Socket在第一步时,需要建连才能开始通信

    在GCDAsyncSocket中提供了四种初始化的方法

    - (id)init;

    - (id)initWithSocketQueue:(dispatch_queue_t)sq;

    - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;

    - (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;

    @property(atomic,weak,readwrite)id delegate;

    @property(atomic,assign,readwrite)dispatch_queue_t delegateQueue;

    - (void)setDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;

    sq是socket的线程,这个是可选的设置,如果你写null,GCDAsyncSocket内部会帮你创建一个它自己的socket线程,如果你要自己提供一个socket线程的话,千万不要提供一个并发线程,在频繁socket通信过程中,可能会阻塞掉,个人建议是不用创建

    aDelegate就是socket的代理

    dq是delegate的线程

    必须要需要设置socket的代理以及代理的线程,否则socket的回调你压根儿就不知道了,

    比如:

    self.socket= [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

    接着,在设置代理之后,你需要尝试连接到相应的地址来确定你的socket是否能连通了

    - (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError**)errPtr;

    host是主机地址,port是端口号

    如果建连成功之后,会收到socket成功的回调,在成功里面你可以做你需要做的一些事情,我这边的话,是做了心跳的处理

    - (void)socket:(GCDAsyncSocket*)sock didConnectToHost:(NSString*)host port:(UInt16)port

    如果建连失败了,会收到失败的回调,我这边在失败里面做了重连的操作

    - (void)socketDidDisconnect:(GCDAsyncSocket*)sock withError:(NSError*)err

    重连操作其实比较简单,只需要再调用一次建连请求,我这边设置的重连规则是重连次数为5次,每次的时间间隔为2的n次方,超过次数之后,就不再去重连了

    - (void)socketDidDisconnect:(GCDAsyncSocket*)sock withError:(NSError*)err {

    _status= -1;

    if(_reconnection_time>=0 && _reconnection_time <= kMaxReconnection_time) {

    [_timer invalidate];

    _timer=nil;

    int time =pow(2,_reconnection_time);

    _timer= [NSTimer scheduledTimerWithTimeInterval:time target:selfselector:@selector(reconnection) userInfo:nil repeats:NO];

    _reconnection_time++;

    NSLog(@"socket did reconnection,after %ds try again",time);

    }else{

    _reconnection_time=0;

    NSLog(@"socketDidDisconnect:%p withError: %@", sock, err);

    }

    }

    这里我用status来标记socket的连接状态

    那么socket已经建连了,该怎么发起socket通信呢?

    你需要和后端开发人员商定好socket协议格式,比如:

    [NSString stringWithFormat:@"{\"version\":%d,\"reqType\":%d,\"body\":\"%@\"}\r\n",PROTOCOL_VERSION,reqType,reqBody];

    中间应该大家都能看得懂,那为什么后面需要加上\r\n呢?

    这个\r\n是socket消息的边界符,是为了防止发生消息黏连,没有\r\n的话,可能由于某种原因,后端会收到两条socket请求,但是后端不知道怎么拆分这两个请求

    同理,在收到socket请求回调时,也会根据这个边界符去拆分

    那为什么要用\r\n呢?

    而且GCDAsyncSocket不支持自定义边界符,它提供了四种边界符供你使用\r\n、\r、\n、空字符串

    在拼装好socket请求之后,你需要调用GCDAsyncSocket的写方法,来发送请求,然后在写完成之后你会收到写的回调

    [self.socket writeData:requestData withTimeout:-1 tag:0];

    timeout是超时时间,这个根据实际的需要去设置

    这个是写的回调

    - (void)socket:(GCDAsyncSocket*)sock didWriteDataWithTag:(long)tag;

    在写之后,需要再调用读方法,这样才能收到你发出请求后从服务器那边收到的数据

    [self.socketreadDataToData:[GCDAsyncSocket CRLFData] withTimeout:10 maxLength:50000 tag:0];

    [GCDAsyncSocket CRLFData]这里是设置边界符,maxLength是设置你收到的请求数据内容的最大值

    在读回调里面,你可以根据不同业务来执行不同的操作

    - (void)socket:(GCDAsyncSocket*)sock didReadData:(NSData*)data withTag:(long)tag;

    最后一个则是断开连接,这个只需要调用

    [self.socket disconnect];

    ok,这样的话,最简单基础的socket通信,你已经大致能完成了~

    ----------------------------------------------------

    2016.4.26更新

    有人提问说在网络环境以及其他因素下,很有可能会造成客户端或者后端没有接收到回调或者请求,那该怎么办呢?

    我们需要加上消息回执的处理

    客户端发出请求的时候,可以将该请求放到存到数组里面,等到后端的相应回调,如果该请求超时,说明后端没有接收到我们的请求,我们可以将该请求重新发送

    客户端接收请求的时候,后端将数据发给客户端,客户端需要增加回执处理,告诉后端,客户端接收到数据了,如果后端没接收到,也重新推一遍数据,客户端和后端双向保护解决丢失问题

    2016.8.5更新

    有些时候,不能定位是否是后端问题还是客户端/SDK问题的时候,可以用命令行抓一下socket包看看(用Charles只能抓http和https包)

    命令行如下:

    sudo tcpdump -i any -n -X port 7070

    Tip:7070端口号请根据实际的调试端口号修改

    效果如下:

    红色部分就是socket包的内容了

    如果有什么意见或者建议,欢迎大家留言,知识是需要交流的,我相信会有更好更简洁的方法来处理

    这个是我的个人微信公众号,会不定期发表一些iOS开发文章以及疑难问题和我在阅读技术和非技术书籍的一些感悟,欢迎大家订阅!

    宫城Dev

    相关文章

      网友评论

      • DSperson:请问 你们 实在主线程 读取数据?
      • aloris:小宝贝,二维码过期了,可以拉我一下嘛,你重新更新下
        宫城_:@xuMao ok了
      • MUYO_echo:大神,您好,我目前服务器可以链接成功,然后在- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port方法中给服务器发送登陆验证,开启读入流,但是didReadData方法不执行,是没有收到服务器消息吗?didReadPartialDataOfLength这个方法中打印,值一直为25,求大神指导,我qq,1020351736,万分感谢
        MUYO_echo:@青涝的大树 已经解决了,是边界符的问题。谢谢大佬
        青涝的大树:连接服务器之后,是不是没有主动readData
      • iOS_小张:感谢分享,可否加一下好友,部分细节问题想请教一下您,qq:254654243
      • 773f0db0e614:在didReadData读取回复数据时,有时一次返回数据,有时分几次返回数据,这种情况怎么处理?拼包吗?
      • 小学生课代表:大神你好,我想问一下,在你这个demo里,我在服务端返回什么能保证心跳?我在运行你的demo的时候,第一次发送reqType=7的那个模型时我设置服务器直接原封不动返回.然而在走到发送心跳包的时候也如此,在发送完心跳包之后就会马上进入到客户端收到信息的代理方法里,打印data是有值的,打印jsonstring为nil..然后就崩在这了?我没找到问题的原因以及解决办法,望告之..非常感谢
      • 大雄君噢:连接成功后 给后台 readDataWithTimeout 发数据 后台完全接收不到啊 怎么办啊 大神
      • 冬ge:一链接上 过一会就断开 什么原因啊 求教 2017-10-18 11:08:45.766027+0800 GCDAsyncSocketManagerDemo[3009:92968] Cool, I'm connected! That was easy.
        2017-10-18 11:08:58.683046+0800 GCDAsyncSocketManagerDemo[3009:92968] socketDidDisconnect:0x7fac79d0d0c0 withError: Error Domain=GCDAsyncSocketErrorDomain Code=4 "Read operation timed out" UserInfo={NSLocalizedDescription=Read operation timed out}
        宫城_:@冬ge 你看下是哪个请求超时了
      • 20406e2f0d9f:您好楼主
        有这个可以实时监听后台数据,实时获取后台数据吗
        青涝的大树:后台可以推送数据给client
      • f6cd93cfa5b4:您好?并发的线程是指线程并发执行么? 那么线程是串行的还是并行的?为何并发的线程会阻塞呢?
      • WARRON:如果是个小白看你的代码,会特别伤感,建议多加注释,
      • WARRON:还有管理类最好只有一个 你弄成了两个, 而且GCDAsyncSocket的代理方法显得混乱了一些
      • WARRON: 我建议socket不做成单利类,
      • YDomo:感谢分享,请问大神有建qq谈论群吗? 或者能加下大神qq吗,还有些socket方面的问题想讨教一下,在下qq643934580
      • MrD董:你好从服务器返回数据的回调在哪里设置呢
        宫城_:@MrD董 在你设置的代理类里面实现
      • __weak:大神楼主,我现在在做GPS定位方面的,就像共享单车那些一样的,菜鸟想问问你是不是需要用到这个第三方啊?
        __weak:@宫城_ 需要的
        宫城_:@__weak 实时
        宫城_:@__weak 你需要事实上报地理位置么?
      • 26b5cc676194:楼主 我在做长连接的需求 看了你的Demo 有些地方不明白 能不能请教一下 我的QQ:190934816
      • 773f0db0e614:向服务器分包发送文件怎么分包啊?
      • 33ddfe5114f8:大神,请教你一个问题。初始化 socket, _connectConfig.token = @"****"; 这个token是后台提供的吗?望解答
        773f0db0e614:向服务器分包发送文件怎么分包啊?
        宫城_:@Achene 是的
      • f367c38c26f7:首先感谢楼主的分享,我现在遇到一个问题,如果一个控制器内有两个甚至多个请求的时候怎么写这个链接,我是在didReadData方法里面得到数据之后又进行了另一个链接请求,问题就是有时会第二个请求链接不上,请问楼主这样的问题怎么解决比较好?
        f367c38c26f7:@宫城_ 能不能详细一点,谢谢了
        宫城_:@userID 短连接可以用AFN去处理,请求依赖的话在回调里面做
        f367c38c26f7:用的是短连接
      • 谢谢生活:这盘是真遇到问题了,楼主,如果我用socket发出一个请求后,socket刚好断开了连接,那么这个时候就没有didReadData回调了。那么socket发出的请求怎么做到失败回调呢??
        谢谢生活:@谢谢生活 你扣扣好多,我扣扣请教你,谢谢
        谢谢生活:@宫城_ 没有看到呢?在哪里,我做不来
        宫城_:@谢谢生活 有一个读超时的回调,可以在这个回调里面做
      • 谢谢生活:感觉楼主分享技术,最佩服的人就是布道者。
      • changeWong:我想问问,你的服务器端是不是也用ios来写的?我这边遇到多个客户端同时向服务器端请求数据时,服务器端发送的数据会乱掉
        changeWong:@宫城_ 我这边的需求是在ios设备之间传输文件,所以服务器端也是在ios下用GCDAsyncSocket写的
        宫城_:@changeWong 服务端用java去做的,你的服务端是否没有维护多个客户端的连接关系
      • angelababa:请问有做网络切换处理么
        宫城_:但是它不能区分网络状态吧
        angelababa:@宫城_ 。。。。GCDAsyncSocket 自带断网检测。。
        宫城_:@angelababa 可以用AF的网络监测来做处理
      • blues_9d41:收到的返回的数据缺少了一部分该怎么做,是丢失了 还是需要再次接受,, 是怎么个做法。。
        blues_9d41:@宫城_ 被拆包了 怎样多次接受? 那个max的接受方法是有限范围呀
        宫城_:@blues_9d41 你指的是数据丢失还是数据被拆包了?
        blues_9d41:求加个好友 982466338
      • 12e6755290f5:我socket连接成功以后,经常断开,这有可能是什么原因?
      • Curry_J_X:你好,GCDAsyncSocket如何创建多个TCP长连接

        @interface ViewController : NSViewController
        {
        @private
        GCDAsyncSocket *asyncSocket1;
        GCDAsyncSocket *asyncSocket2;
        }

        这是第一个连接 :
        dispatch_queue_t mainQueue = dispatch_get_main_queue();

        asyncSocket1 = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];

        {
        NSString *host = @"192.168.1.101";
        uint16_t port = 8080;


        NSLog(@"Connecting to \"%@\" on port %hu...", host, port);

        NSError *error = nil;
        if (![asyncSocket1 connectToHost:host onPort:port error:&error])
        {
        NSLog(@"Error connecting: %@", error);
        }
        }
        第二个连接如下
        asyncSocket2 = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
        {
        NSString *host = @"192.168.1.102";
        uint16_t port = 8080;


        NSLog(@"Connecting to \"%@\" on port %hu...", host, port);

        NSError *error = nil;
        if (![asyncSocket connectToHost:host onPort:port error:&error])
        {
        NSLog(@"Error connecting: %@", error);
        }
        }
        现在我想连的服务器不确定几个,我该怎么建立n个socket连接呢?即一个 GCDAsyncSocket client 实例如何建立多个TCP连接 ?
      • china码农:你好,我这边也是在做智能硬件方面,第一次做。需要实现链接到特定端口的WiFi或者蓝牙,我看了下你的Demo,这边的设计思路就是连接到特定的WiFi,有ip地址和端口号,其他就可以正常通信了是吧,跟我之前用afnet调接口一样?
        宫城_:@china码农 需要后面调用readData方法
        china码农:@宫城_ 你好我想问下,我用self.socket writeData:xmlData withTimeout:1 tag:0 ,这个方法发送数据为何只发送一次后面没有了
        宫城_:@china码农 是的,推荐连接域名地址,调用接口封装成http请求形式便于理解
      • 630c5eeb35d3:用sudo tcpdump -i any -n -X port命令行得到的数据是客户端发出去的,还是硬件返回的
        宫城_:@sunny68 发出的我没截图,也是json格式显示
        630c5eeb35d3:@宫城_ 你的截图中json的是收到的,json左边的二进制是发出去的?
        宫城_:@sunny68 都可以,能抓到你发送和接收的shu ju bao
      • 迷恋代码:楼主,关于TCP拆包和连包的问题能否加个QQ请教一下你,492262370@qq.com,谢谢
      • 迷恋代码:楼主,这个框架的超时时间最长可以设多久有测过吗,我测的时间超过16秒后,就不会调用这个框架的超时方法
      • liwuJs:楼主,我想问下,重连后客户端发送请求就被服务器端断开是什么原因?
      • 天下无贼:谢谢 分享
      • 景彧:宫城大神,求加qq好友啊,我的qq:657744858.谢谢。
      • 丶大明:socketDidDisconnect:0x7ffc78c02650 withError: Error Domain=GCDAsyncSocketErrorDomain Code=4 "Read operation timed out" UserInfo={NSLocalizedDescription=Read operation timed out} 过段时间会自己断掉 :sob:
        宫城_:@丶大明 服务器地址改成你自己的了么?
        丶大明:@宫城_ 我是用你的demo 刚开始发了一条,放着过了10多秒就自己掉了
        宫城_:@丶大明 是不是你有请求没有收到响应?
      • 7426426529e1:您好,我的代码是按照你的顺序来做的,先建立连接,连接成功。我做的是跟跑步机实时连接,跑步机动,我这边显示数据,我先发了一串字符串和跑步机绑定,跑步机动,服务器能收到它的数据而我这边的读取数据的代理方法不走。这是为什么呢?希望您可以解答一下。谢谢您
        7426426529e1:@宫城_ 感谢您能回复
        7426426529e1:@宫城_ 我在连接成功代理写了readData。在发送成功也写了readData
        宫城_:@Waston_王 是不是你调用writeData方法后没有调用readData方法
      • Weartist:拉倒吧
      • Uleen:有连接池功能的吗?
      • JopiNFlyyy:请问用GCDAsyncSocket怎么适配Https?
        青涝的大树:用TLS就好了 startTLS
        宫城_:@谢谢生活 没明白...
        谢谢生活:https和socket完全是两个东西啊,端口号都不一样,没法搞哟
      • Uleen:token是用来干什么的
        宫城_:@Uleen 验证客户端的真实性
      • fa9ac582dbcc:能否加个QQ 大神 我还是有很多地方不明白的
        fa9ac582dbcc:搞定了 多谢了!但还是想加个Q方便以后交流 353582753
        宫城_:@流尘同学 好
      • fa9ac582dbcc:能加个Q么 还是有很多地方不懂 最近在做家具类wifi的app 想交流下
      • 出门右转掘金见:看的一知半解的
      • 出门右转掘金见: GACRequestType_ConnectionAuthAppraisal, //连接鉴权
        什么是连接鉴权呀,什么时候出发心跳呢 :pray:
      • 出门右转掘金见:楼主可以加个qq吗,我有些问题还是没搞懂想请教一下.我的qq是1102533858
      • 翀鹰精灵:sudo tcpdump -i any -n -X port 7070 使用这个命令抓包
        出现这些信息什么意思
        tcpdump: data link type PKTAP
        tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
        listening on any, link-type PKTAP (Packet Tap), capture size 262144 bytes


      • 出门右转掘金见:请问什么时候用这个三方,什么时候用xmpp呢
        出门右转掘金见:@Max_Y 能加扣扣聊吗,简书好像不方便 :joy:
        出门右转掘金见:@宫城_ 那个发送心跳那一部分我没看懂呀,能给我讲一下吗
        宫城_:@Max_Y xmpp比较耗流量...现在用的都比较少
      • guoshengboy:我想问一下 超时时间有什么用?假如超时了 怎么办? :smile: 重新发送? :smile:
        guoshengboy:@宫城_ 我现在用GCDAsyncSocket和服务端写了一个聊天的Demo 因为公司网好 没出错 我总感觉会出问题 我应该注意什么问题 ?
        宫城_:@guoshengboy 设置超时,可以在超时的代理里加重发或者提示,会有返回失败的情况
        guoshengboy:@guoshengboy 假如我写成功了 服务端那边返回失败了 会出现这样的情况吗?
      • Grass888:首先感谢楼主分享的技术。我最近正在做类似的项目,有些问题不知道怎么解决,希望能得到楼主的帮助。现在我为了完成长连接在socketDidDisconnect:方法中进行了socket 的初始化,也就是说,每次失败都重新初始化。这样做感觉不对,我该怎么做?还有就是,每次发送消息会发2-3条,但是我只调用了1次发消息的方法啊?
      • LaiBit:您好,這是我看果最詳細的教學了
        請問 我在使用上發生一個問題想請教你
        環境是 iPad 連線 樹莓派,區域網路連線,iPad是client端, 樹莓派是Server端
        如果在運行期間,忽然把樹莓派網路拔掉,我iPad這邊是沒有辦法馬上知道斷線
        要等待一段時間才能知道斷線了

        想說你是不是知道GCDAsyncSocket有什麼方法可以知道呢?

        宫城_:@LaiBit - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;这个方法要过段时间才触发么?目前我是通过两种方式来判断,一个是前面这个代理方法,另一个是通过心跳的方式,超过一定次数未收到心跳响应之后,判断为断开
      • 3bd02cdda22d:感谢楼主,写的很详细,正好借鉴你的思路!
        但是有一个问题,所有的都正常连接,但是在接收数据的时候,如果一个请求服务器返回大量数据会分包返回给我,但是我只能收到一部分,5条只能收到3-4条,就收不到了 .我们这边服务器返回的都是结构体数据,每次也都打印了 大概就只能接受5000字节的数据,大于的就接受不到了 但是服务器确实给了!求教
        宫城_:@2011少 - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag; length设置大小
        3bd02cdda22d:怎么设置不限大小呢 没有找到 我 qq 562797023 请请教
        宫城_:@2011少 你看下设置readData的数据大小的地方,设置成不限大小试下
      • fe5cd9ac0a4d:好的 谢谢您, 还有一个问题就是 为什么还要在发送成功的代理里面写一句读的代码, 是自己发送,服务器并没有返回什么,为什么要读 如果有服务器给我数据不是应该会掉接受数据哪个方法么 如果不写这句会有什么后果 而且这个方法也没油返回值,读的结果是什么
      • fe5cd9ac0a4d:您好,我现在做智能硬件,以前没有接触过,一边学一边做,选择用GCDAsyncSocket来开发,看是看懂了,但是在是开发中遇到不少问题,可以帮忙解决么
        宫城_:@带着灵魂去撸串 恩,可以,现在我的项目也是这样
        fe5cd9ac0a4d:@宫城_ 因为这段时间接触的东西比较多,大半年没有接触过iOS,重新搞发现有点蒙,我先说一下我对这个的思路,有不对的地方帮忙指正一下。因为全局只有一个连接,我写了一个单例,单例里只实现了连接,发送消息,断开连接三个方法可以供其他文件调用,然后在在需要连接的控制器里用单例调用开始连接的方法,然后遵循协议,实现代理方法,需要接受数据的控制器同样遵守协议,成为socket的代理,实现代理方法。我大致的思路是这样,请指点一下
        宫城_:@带着灵魂去撸串 嗯,你在评论里问我就好了
      • guoshengboy:我想问一下 假设我在处理服务器发来的数据中 突然服务器又发来一条数据 我怎么办呢 ? 我要等第一条数据处理完才能处理第二条 所以我加个串行队列 但是加了好像socket就不能用了
        宫城_:@guoshengboy 你试下在加入到串行队列之后,调用readData方法,保证socket能继续获取到服务器的数据
      • 千客:加我下1728283676 有问题讨论下
      • 独爱ii:大神导入你框架#import <JSONModel/JSONModel.h>文件找不到,去你Demo里不知道在什么地方,我的框架都是手动导入的
        宫城_:@独爱ii 在podfile里面导入
      • 234d35b7bdf9:大神,我用了你这个流程。发心跳包出去。但是收不到服务器返回的信息。本地收不到服务器返回的数据。
        宫城_:@洋葱1111 是不是在请求之后没有调GCDAsync的read方法
      • 234d35b7bdf9:求加大神好友 qq530298846.有问题想问你您
      • 234d35b7bdf9:大神求demo啊。。qq发我也行。530298846 :relaxed:
        宫城_:@洋葱1111 GitHub上有
      • viveco:楼主问你个问题,我连接成功了会走didConnectToHost这个方法,失败走这个socketDidDisconnect这个方法,但是后台说连接上应该会返回一个数据,didReadData这个方法里面没有是怎么回事啊?求教一下
      • 4da62785c5a7:楼主,我有点问题想要问你,很急,可否加好友详细说下1023919443,万分感谢
      • Joolybgo: 大神, GCDAsyncSocket 的代理是用一个类来管理发送数据 接受数据 还是分散到各个控制器 这2种那个好啊, 我看你们现在用的是分散到各个控制器是吧, 把代理传出去了, 第一种不好吗
        Joolybgo:@宫城_ 用for循环来请求, 为啥管理回调block的数组会改变啊, 比如循环10次, 可能就收到2次数据, 第2个数据还不对
        宫城_:@ZL_October 用一个类管理较好
      • Joolybgo:楼主,有个问题需要请教一下你。能否帮我解答一下,我现在需要要弄一个账号只能一端登录, 能加qq详聊吗 我的qq: 1770421128
      • 肉身佛陀:GCDAsyncSocketManager这个类是你开源的么?其中那个model类中,字典转化为json字符串,使用的NSData *stringData =
        [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:&error];只要把options置0,得到的data通过UTF-8转字符串就是无格式的jsonStr;
        直接用""(空)替换" "(空格)会替换掉所有的,会出事的
      • 策马鞭程:楼主,为什么服务端发送数据大并且频繁,会出现客户端延迟接收的问题?
      • c2fffd2b0090:作者大神你好,我最近也做 socket 聊天,能加你为好友吗? 或者留下我的联系QQ 1736591423 方便问一些问题
      • f2fce1ee459c:大神能不能加下我,也在做socket,有些问题想请教下,584911253qq
      • f6a7c393f2ad:大神,我想咨询您个问题
        我这里有个需求类似于给服务端发送更新包,简单来说就是连续发送很多个包,但是我的循环不知道哪里有问题,总是收不到返回的信息,有人说是我没有开辟线程池什么的,叫我加上runloop,想问您一下,如果要是连续发送很多包,这个循环该怎么弄啊
        宫城_:@linjoe 这个你要检查一下了,我直接就是递归请求
        f6a7c393f2ad:@宫城_ 没有呢,我设置的-1,感觉像是我循环写错了
        宫城_:@linjoe 有没有超时了?
      • 海泉:楼主好!我改了HOST和PORT,这样调用的 [[GCDAsyncSocketCommunicationManager sharedInstance] createSocketWithToken:@"your token" channel:@"your communication channel"];,但是报错如下:
        2016-09-03 11:37:22.050 GCDAsyncSocketManagerDemo[1694:48314] socketDidDisconnect:0x7f8fd3667880 withError: Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused" UserInfo={NSLocalizedDescription=Connection refused, NSLocalizedFailureReason=Error in connect() function}
        2016-09-03 11:37:22.086 GCDAsyncSocketManagerDemo[1694:48314] socketDidDisconnect:0x7f8fd3677390 withError: Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused" UserInfo={NSLocalizedDescription=Connection refused, NSLocalizedFailureReason=Error in connect() function}
        2016-09-03 11:37:23.055 GCDAsyncSocketManagerDemo[1694:48314] socketDidDisconnect:0x7f8fd3677390 withError: Error Domain=NSPOSIXErrorDomain Code=61 "Connection refused" UserInfo={NSLocalizedDescription=Connection refused, NSLocalizedFailureReason=Error in connect() function}
        2016-09-03 11:37:25.477 GCDAsyncSocketManagerDemo[1694:48314] socket 未连通
        2016-09-03 11:37:26.075 GCDAsyncSocketManagerDemo[1694:48314] socket 未连通
        2016-09-03 11:37:26.275 GCDAsyncSocketManagerDemo[1694:48314] socket 未连通
        2016-09-03 11:37:26.473 GCDAsyncSocketManagerDemo[1694:48314] socket 未连通
        2016-09-03 11:38:09.386 GCDAsyncSocketManagerDemo[1694:48314] socketDidDisconnect:0x7f8fd37125e0 withError: Error Domain=GCDAsyncSocketErrorDomain Code=3 "Attempt to connect to host timed out" UserInfo={NSLocalizedDescription=Attempt to connect to host timed out}
        是什么原因呢?帮忙指点指点。
        宫城_:@海泉 因为我看到日志里面打出来socketDisconnect日志,所以初步判断是地址连不通,所以telnet试试看,是否是本地无法连通
        海泉:@宫城_ 恩,telnet是远程登录系统的意思吗?地址是通的,安卓的小伙伴已经测试了,“以及你建立连接时发送的请求,后端是否能正确解析”,是要先建立连接再发送数据吗,它是UDP连接吗
        宫城_:@海泉 你看下telnet你的地址,是否是通的,以及你建立连接时发送的请求,后端是否能正确解析
      • Amy莫莫:我第一次用这个库没有遇到问题,第二次用连接上了服务器之后,没多久就自动断开,我设置了重连,但是依然没多久就断开,收不到后台发过来的消息,不知道是为什么
        宫城_:@树上蚍蜉 字典转的时候要去掉空格和换行符 :smile:
        Amy莫莫:@宫城_ 我知道原因了,是因为我用字典转json的方法不对,导致json格式错误,所以发过去的请求,后台无法解析
        宫城_:@树上蚍蜉 心跳有接收到么
      • Formutolar:楼楼可以 qq 加个好友吗,有些个问题想问问312948666
      • 我的时代我开创:gcdasyncsocket-server-receive-data-only-first-time
        楼主 这个问题怎么解决啊?
        我已经通讯连接了,但是为什么发送第二次数据是可以的,却接收不了第二次数据啊?
        好忧伤啊,能加个qq详聊吗?或者我把demo发你帮我看下啊,谢谢啦
        我的时代我开创:@宫城_ 475396892
        谢谢啦
        宫城_:@我的时代我开创 你的qq多少?
      • 1条大菜狗:楼主,有个问题需要请教一下你。能否帮我解答一下,我们用的protocol buffer,跟你请教个问题。
        1条大菜狗:@宫城_ 加我qq,详细问下你。可好。568692139
        宫城_:@1条大菜狗 嗯,什么问题?
      • 温暖的弦Y:很浅显易懂,入门轻松,哈哈
      • Wanto:感谢作者分享

        刚入iOS的坑,这里关于初始化时候的队列问题没有弄明白,劳烦楼主帮忙看看。

        就是初始化时候我们一般这么做 [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        但如果我将这个处理封装在一个库中,再由另一个程序去调用,那么这里的initWithDelegate和delegateQueue该如何处理,我才可以在库中就能够直接使用委托来获得回调结果,比如我在封装的库中去调用 -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port,这个是没法被触发到的

        应该如何初始化委托和队列,才能够直接在库中去触发回调呢?
        宫城_:@泽轩 不会呀,Pods导入的时候link的也是静态库,delegate设置应该是不会有问题的
        Wanto:@宫城_ 是的,如果我在主程序里去做 initWithDelegate -> Connect -> didConnectToHost,是可以正常触发的,但如果我把这个流程放到库里边去(.a),那么在这个库里边没法去到didConnectToHost。我猜测是delegateQueue不该用main)queue,但不知该如何处理
        宫城_:@泽轩 初始化的处理全部封装在库里,只需对外提供的接口比如- connect方法,你现在碰到的问题是-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port这个代理没有被触发么?
      • 1条大菜狗:你写这个能做什么?解包的算法有么,使用protocol buffer怎么用。使用json传输好呢,还是protocol buffer好呢?开多少个线程好呢?什么时候使用代码锁呢
        宫城_:@1条大菜狗 刚看了下protocol buffer,是个二进制协议,这样在传输和数据包大小方面应该优于json的
        宫城_:@1条大菜狗 protocol buffer这个我没怎么去了解过,不是很清楚,所以没有和json传输没有比较过,目前我们用的是json传输,最佳线程的处理我觉得可以根据运行当前进程的系统处于激活状态的处理器数量来自己管理,我觉得数据包不大直接发就好,不需要锁
      • fonglaaam:请教一下 同一ViewController有多个请求的需求 创建一个socket writeData过去以后 回调ReadData里面的tag无法区分请求是哪个。这种情况下 要怎么解决呢?是用多线程创建socket,一个请求一个线程,再在viewcontroller里分别调用比较好吗?这个思路对不对?如果对要怎么实现呢?
        宫城_:@1条大菜狗 我们目前用的是微秒级的时间来作为唯一标识,确实会存在重复的可能性,但是能大大降低重复性的概率
        1条大菜狗:@林晚晚lam 一个请求一个线程,这样不好吧。还有有时候唯一的标示也不是那么好用的。这个唯一性不是太好保证。
        宫城_:@林晚晚lam 最简单的做法就是在Write的时候加一个唯一标识进去,然后请求返回的时候,让后端将这个标识返回回来做对比
      • 国王or乞丐:啊啊啊,楼主,救命啊,你那里可否有Demo,供参考的,或者我们加个联系方式吧求qq:1030554941,谢了
        宫城_:@简单的云 ok
        国王or乞丐:@宫城_ 哥,加个好友吧,还有好多问题想问问你呢
        宫城_:@简单的云 github上有使用demo
      • 大熊iOS:楼主,看了你的文章,自己下了demo,在创建socket之后connect总是不成功。能否留下联系方式,请教一下。谢谢
        大熊iOS:@宫城_ 还想请问一下- (void)createSocketWithToken:(nonnull NSString *)token channel:(nonnull NSString *)channel里面的token和channel送的都是什么值
        大熊iOS:@宫城_ self.socket connectToHost:HOST onPort:PORT withTimeout:TIMEOUT error:&error改成我后台的的ip地址和端口号,但是连接不成功。
        宫城_:@大熊iOS socket地址改了么?
      • 吃你煮的鱼:楼主有使用中出现 把应用退到后台 时间长了进入前台socket会崩溃的情况吗
        宫城_:@吃你煮的鱼 你最好在退到后台的时候断开socket连接,回前台再去建连
        吃你煮的鱼:@宫城_ crash在重连socket那里 到后台长时间不用的话 socket不是会断吗 然后就很容易出现这情况 不知道是不是我没用对
        宫城_:@吃你煮的鱼 没有,crash在哪里?
      • 呵呵x3:前后端定义socket通讯的消息体格式,如果考虑使用 json 怎么样?
        宫城_:我们用的就是json
      • 菜鸟晋升路:你没有写一个demo吗?
      • 系统盘:怎么得到接收数据的总大小和实时大小,也就是进度
      • 343cea0f7107:请问一下,iOS客户端如果一秒内收到或发出多条(例如100条)数据,该如何处理才能保证不会漏包呢?
        宫城_:@JcccZ 哈哈,好,发出请求的时候,可以将该请求放到存到数组里面,等到后端的相应回调,如果该请求超时,说明后端没有接收到我们的请求,我们可以将该请求重新发送,接收的时候,后端将数据发给客户端,客户端需要增加回执处理,告诉后端,客户端接收到数据了,如果后端没接收到,也重新推一遍数据,客户端和后端双向保护解决丢失问题
        343cea0f7107:@宫城_ 可以具体点嚒 :joy: :joy:
        宫城_:@JcccZ 消息回执
      • iOS之星: 大神非常感谢你的分享 我想请教一下 实际用封装好的 项目用的 socket demo么 我按照你的方法 做 但是实际上这样创建的socket连接 老是会不断断开 但我要的是稳定的长连接
        _reconnection_time和kMaxReconnection_time是什么的属性 是不是设置了初始值
        宫城_:@谢谢生活 在没有收到后端返回心跳的时候,用这个上限值来判断是否和后端断开了,这个可以根据需要修改
        谢谢生活:我看代码是心跳次数的 上线值 可以根据自己的修改
      • 042a0e1be73f:谢谢,学习了!withTimeout:-1是什么意思,超时时间为什么是-1呢?
        宫城_:嗯,这个是我实际项目中的demo,经常断开这个问题有一种可能是和网络有关,我在使用的过程中,有时候公司网络不好,会出现断开的情况
        iOS之星:大神非常感谢你的分享 我想请教一下 实际用封装好的 项目用的 socket demo么 我按照你的方法 做 但是实际上这样创建的socket连接 老是会不断断开 但我要的是稳定的长连接
        宫城_:@iiOS 设置一个负值就是没有超时时间
      • mark666:没啥用
      • 8ae158dda3f2:嗯,明天研究一下,有问题再请教。
        宫城_:@_NevinZ 好的

      本文标题:iOS 基于GCDAsyncSocket快速开发Socket通信

      本文链接:https://www.haomeiwen.com/subject/dvxkkttx.html