美文网首页iOS进阶不易的地方
Socket通信之GCDAsyncSocket用法

Socket通信之GCDAsyncSocket用法

作者: 可能是含钙最高的钙钙 | 来源:发表于2016-07-04 02:45 被阅读431次

    这篇文章只是简单记录下GCDAsyncSocket用户端的简单用法,后续我会把os层基于C的 BSD socket,Core Foundation层的CFNetWork以及cocoa层的NSStream简单用法整理出来,以备今后查询.各位大神如果有深入的研究的或者有什么好的使用技巧了都可以交流下哦,欢迎指出使用不当之处.

    Socket

    • 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket
    • socket又称"套接字", 应用程序通过"套接字"向网络发出请求或者应答网络请求.
    • socket常用的网络请求TCP和UDP
      根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。
      (1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态.
      (2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字.为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求.
      (3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了.而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求.
    • Socket的通信流程图
    Snip20160707_1.png

    GCDAsyncSocket用法

    -创建Socket对象.GCDAsyncSocket中socket链接后的事件处理都是在代理里面的

        // 创建Socket对象
        // 设置代理,让代理在全局队列中调用
        GCDAsyncSocket *clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
        // 用强指针引用着Socket对象
        self.clientSocket = clientSocket;
        
        NSString *host = nil;
        uint16_t port = 8288;
        // 连接服务器
        NSError *error = nil;
        
        [clientSocket connectToHost:host onPort:port error:&error];
        if (error) {
            NSLog(@"%@", error.localizedDescription);
        }
    
    • 常用的几个代理,GCDAsyncSocketDelegate.注意:在链接成功之后要监听数据的读取,接收到数据后也要监听数据的读取,接收数据的代理不会被回调.
    // 连接成功后的回调
    - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
        
        // 监听读取数据
        [sock readDataWithTimeout:-1 tag:0];
        
    }
    
    // 与服务器断开连接后的回调
    - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
        // 可以调用该方法查看断开连接的原因
        NSLog(@"%@", err);
    }
    
    // 接收数据的回调
    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
        // 接收到的消息
        NSString *messageStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", messageStr);
        
        //  准备读取下次的数据
        [sock readDataWithTimeout:-1 tag:0];
        
    }
    
    • 发送消息
    /**
     *  发送消息
     *
     *  @param sendMessage 发送的消息内容
     */
    - (void)sendMessage:(NSString *)sendMessage{
        
        if (sendMessage == nil || sendMessage.length == 0) {
            return;
        }
        
        // 发送
        [self.clientSocket writeData:[sendMessage dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
        
    }
    
    // 发送消息成功后的回调,消息发送成功后可以在这个代理里面做一些处理
    - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
        
        
    }
    

    相关文章

      网友评论

      • 等这姑娘老在我心里:如何重启服务端呢
      • Wanto:感谢作者分享

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

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

        应该如何初始化委托和队列,才能够直接在库中去触发回调呢?
        Wanto:@Irini钙钙 谢谢!后来发现是我初始化的对象的作用域的问题,将封装的库的对象放在调用方法外初始化可以实现触发,而不是在调用时候才去初始化

        有另一个问题,接收数据都是通过回调方式来处理。但如果我不想对上层暴露Socket细节,用户只需要传IP过来,然后告诉我他要获取一个什么,我就直接给它他什么,应该如何处理呢?
        Q171063456 方便的话还请交流一下
        可能是含钙最高的钙钙:@泽轩 不好意思,刚看到.
        你可以在你封装的工具类里提供相应的代理方法,这些代理方法的调用放到GCDAsyncSocket代理方法里面.另一个程序调用的时候,直接实现你定义的代理方法去接受结果.如果还不行了,你把你扣扣留下,我加你扣扣再深入讨论.希望能共同进步.
        MyMiaBaby:@泽轩 看不懂

      本文标题:Socket通信之GCDAsyncSocket用法

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