iOS 网络(GCDAsyncSocket源码分析)

2,940 阅读26分钟

前言

CocoaAsyncSocket是谷歌的开发者,基于BSD-Socket写的一个IM框架,它给Mac和iOS提供了易于使用的、强大的异步套接字库,向上封装出简单易用OC接口。省去了我们面向Socket以及数据流Stream等繁琐复杂的编程。
这个就是整个库的类,一个是基于TCP,一个基于UDP,这篇文章主要是介绍GCDAsyncSocket的源码

GCDAsyncSocket源码分析

socket的客户端和服务端流程大概如下,大多数情况下我们都是基于客户端开发的,所以我们分析的流程就按照客户端的流程走:

先来看GCDAsyncSocket这个类的属性

@implementation GCDAsyncSocket
{
    //flags,当前正在做操作的标识符
    uint32_t flags;
    uint16_t config;
    
    //代理
    __weak id<GCDAsyncSocketDelegate> delegate;
    //代理回调的queue
    dispatch_queue_t delegateQueue;
    
    //本地IPV4Socket
    int socket4FD;
    //本地IPV6Socket
    int socket6FD;
    //unix域的套接字 // 进程通讯  locahost VS 127.0.0.1
    // socket
    int socketUN;
    //unix域 服务端 url
    NSURL *socketUrl;
    //状态Index
    int stateIndex;
    
    //本机的IPV4地址  --- 地址host interface
    NSData * connectInterface4;
    //本机的IPV6地址
    NSData * connectInterface6;
    //本机unix域地址
    NSData * connectInterfaceUN;
    
    //这个类的对Socket的操作都在这个queue中,串行
    dispatch_queue_t socketQueue;
    
    // 源 ---> mergdata  get_data buffer tls ssl CFStream
    // data
    dispatch_source_t accept4Source;
    dispatch_source_t accept6Source;
    dispatch_source_t acceptUNSource;
    
    //连接timer,GCD定时器 重连
    dispatch_source_t connectTimer;
    dispatch_source_t readSource;
    dispatch_source_t writeSource;
    dispatch_source_t readTimer;
    dispatch_source_t writeTimer;
    
    //读写数据包数组 类似queue,最大限制为5个包 - FIFO
    NSMutableArray *readQueue;
    NSMutableArray *writeQueue;
    
    //当前正在读写数据包
    GCDAsyncReadPacket *currentRead;
    GCDAsyncWritePacket *currentWrite;
    //当前socket未获取完的数据大小
    unsigned long socketFDBytesAvailable;
    
    //全局公用的提前缓冲区
    GCDAsyncSocketPreBuffer *preBuffer;
    	
#if TARGET_OS_IPHONE
    CFStreamClientContext streamContext;
    //读的数据流  ----  c
    CFReadStreamRef readStream;
    //写的数据流
    CFWriteStreamRef writeStream;
#endif
    //SSL上下文,用来做SSL认证
    SSLContextRef sslContext;
    
    //全局公用的SSL的提前缓冲区
    GCDAsyncSocketPreBuffer *sslPreBuffer;
    size_t sslWriteCachedLength;
    
    //记录SSL读取数据错误
    OSStatus sslErrCode;
    //记录SSL握手的错误
    OSStatus lastSSLHandshakeError;
    
    //socket队列的标识key -- key - queue
    void *IsOnSocketQueueOrTargetQueueKey;
    
    id userData;
    
    //连接备选服务端地址的延时 (另一个IPV4或IPV6)
    NSTimeInterval alternateAddressDelay;
}

先来分析这些属性的作用

  • flags:代表socket当前的状态
// flags的枚举
enum GCDAsyncSocketFlags
{
    kSocketStarted                 = 1 <<  0,  // If set, socket has been started (accepting/connecting)
    kConnected                     = 1 <<  1,  // If set, the socket is connected
    kForbidReadsWrites             = 1 <<  2,  // If set, no new reads or writes are allowed
    kReadsPaused                   = 1 <<  3,  // If set, reads are paused due to possible timeout
    kWritesPaused                  = 1 <<  4,  // If set, writes are paused due to possible timeout
    kDisconnectAfterReads          = 1 <<  5,  // If set, disconnect after no more reads are queued
    kDisconnectAfterWrites         = 1 <<  6,  // If set, disconnect after no more writes are queued
    kSocketCanAcceptBytes          = 1 <<  7,  // If set, we know socket can accept bytes. If unset, it's unknown.
    kReadSourceSuspended           = 1 <<  8,  // If set, the read source is suspended
    kWriteSourceSuspended          = 1 <<  9,  // If set, the write source is suspended
    kQueuedTLS                     = 1 << 10,  // If set, we've queued an upgrade to TLS
    kStartingReadTLS               = 1 << 11,  // If set, we're waiting for TLS negotiation to complete
    kStartingWriteTLS              = 1 << 12,  // If set, we're waiting for TLS negotiation to complete
    kSocketSecure                  = 1 << 13,  // If set, socket is using secure communication via SSL/TLS
    kSocketHasReadEOF              = 1 << 14,  // If set, we have read EOF from socket
    kReadStreamClosed              = 1 << 15,  // If set, we've read EOF plus prebuffer has been drained
    kDealloc                       = 1 << 16,  // If set, the socket is being deallocated
#if TARGET_OS_IPHONE
    kAddedStreamsToRunLoop         = 1 << 17,  // If set, CFStreams have been added to listener thread
    kUsingCFStreamForTLS           = 1 << 18,  // If set, we're forced to use CFStream instead of SecureTransport
    kSecureSocketHasBytesAvailable = 1 << 19,  // If set, CFReadStream has notified us of bytes available
#endif
};
  • config:代表了socket协议状态
// config的枚举
enum GCDAsyncSocketConfig
{
    kIPv4Disabled              = 1 << 0,  // If set, IPv4 is disabled
    kIPv6Disabled              = 1 << 1,  // If set, IPv6 is disabled
    kPreferIPv6                = 1 << 2,  // If set, IPv6 is preferred over IPv4
    // 双工 - 半双工
    kAllowHalfDuplexConnection = 1 << 3,  // If set, the socket will stay open even if the read stream closes
};
  • delegate:代理属性,外界传入一个代理的时候这里就会保存,用于一些状态的回调
    • socket创建成功
    • socket关闭
    • socket写入数据
    • socket读取数据
    • socket断开
//代理
__weak id<GCDAsyncSocketDelegate> delegate;
  • delegateQueue:回调使用的队列
//代理回调的queue
dispatch_queue_t delegateQueue;
  • 三种socket
    • 第一种socket4FD,代表的是ipv4类型的socket
    • 第二种socket6FD,代表的是ipv6类型的socket
    • 第二种socketUN,这个是线程间通讯的socket,其他两种类型的socket也可以实现线程间通讯,不过这个这种socket不用走传输层,比较快捷,不过用的地方比较少
//本地IPV4Socket
int socket4FD;
//本地IPV6Socket
int socket6FD;
//unix域的套接字 // 进程通讯  locahost VS 127.0.0.1
// socket
int socketUN;
//unix域 服务端 url
NSURL *socketUrl;
//状态Index
int stateIndex;

//本机的IPV4地址  --- 地址host interface
NSData * connectInterface4;
//本机的IPV6地址
NSData * connectInterface6;
//本机unix域地址
NSData * connectInterfaceUN;
  • 定义dispatch_source_t类型的对象,用于处理数据,这样写性能比较高
// 源 ---> mergdata  get_data buffer tls ssl CFStream
// data
dispatch_source_t accept4Source;
dispatch_source_t accept6Source;
dispatch_source_t acceptUNSource;

//连接timer,GCD定时器 重连
dispatch_source_t connectTimer;
dispatch_source_t readSource;
dispatch_source_t writeSource;
dispatch_source_t readTimer;
dispatch_source_t writeTimer;
  • 定义读写的数组,这样写可以保证每个数据的时序性
//读写数据包数组 类似queue,最大限制为5个包 - FIFO
NSMutableArray *readQueue;
NSMutableArray *writeQueue;
  • alternateAddressDelay:连接备选地址的延时时间
//连接备选服务端地址的延时 (另一个IPV4或IPV6)
NSTimeInterval alternateAddressDelay;

使用流程

// 创建socket
if (self.socket == nil)
    self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
// 连接socket
if (!self.socket.isConnected){
    NSError *error;
    [self.socket connectToHost:@"127.0.0.1" onPort:8090 withTimeout:-1 error:&error];
    if (error) NSLog(@"%@",error);
}
  • initWithDelegate:delegateQueue:源码分析
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq
{
    return [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];
}

- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq
{
    if((self = [super init]))
    {
        delegate = aDelegate;
        delegateQueue = dq;
        
        //这个宏是在sdk6.0之后才有的,如果是之前的,则OS_OBJECT_USE_OBJC为0,!0即执行if语句
        //对6.0的适配,如果是6.0以下,则去retain release,6.0之后ARC也管理了GCD
        #if !OS_OBJECT_USE_OBJC
        
        if (dq) dispatch_retain(dq);
        #endif
        
        //创建socket,先都置为 -1
        //本机的ipv4
        socket4FD = SOCKET_NULL;
        //ipv6
        socket6FD = SOCKET_NULL;
        //应该是UnixSocket
        socketUN = SOCKET_NULL;
        //url
        socketUrl = nil;
        //状态
        stateIndex = 0;
        
        if (sq)
        {
            //如果scoketQueue是global的,则报错。断言必须要一个非并行queue。
            NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
                    @"The given socketQueue parameter must not be a concurrent queue.");
            NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
                    @"The given socketQueue parameter must not be a concurrent queue.");
            NSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                    @"The given socketQueue parameter must not be a concurrent queue.");
            //拿到scoketQueue
            socketQueue = sq;
            //iOS6之下retain
            #if !OS_OBJECT_USE_OBJC
            dispatch_retain(sq);
            #endif
        }
        else
        {
            //没有的话创建一个,  名字为:GCDAsyncSocket,串行
            socketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);
        }
        
        //自己的指针等于自己原来的指针,成二级指针了  看了注释是为了以后省略&,让代码更可读?
        IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;
        
        
        void *nonNullUnusedPointer = (__bridge void *)self;
        
        //dispatch_queue_set_specific给当前队里加一个标识 dispatch_get_specific当前线程取出这个标识,判断是不是在这个队列
        //这个key的值其实就是一个一级指针的地址  ,第三个参数把自己传过去了,上下文对象?第4个参数,为销毁的时候用的,可以指定一个函数
        dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);
        //读的数组 限制为5
        readQueue = [[NSMutableArray alloc] initWithCapacity:5];
        currentRead = nil;
        
        //写的数组,限制5
        writeQueue = [[NSMutableArray alloc] initWithCapacity:5];
        currentWrite = nil;
        
        //设置大小为 4kb
        preBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];
        
        #pragma mark alternateAddressDelay??
        //交替地址延时?? wtf
        alternateAddressDelay = 0.3;
    }
    return self;
}

initWithDelegate:delegateQueue函数比较简单,主要是做了一些初始化的工作

connectToHost:onPort:withTimeout:error:是连接socket的主要函数入口

- (BOOL)connectToHost:(NSString *)host
                onPort:(uint16_t)port
                withTimeout:(NSTimeInterval)timeout
                error:(NSError **)errPtr
{
    return [self connectToHost:host onPort:port viaInterface:nil withTimeout:timeout error:errPtr];
}

//多一个inInterface,本机地址
- (BOOL)connectToHost:(NSString *)inHost
                onPort:(uint16_t)port
                viaInterface:(NSString *)inInterface
                withTimeout:(NSTimeInterval)timeout
                error:(NSError **)errPtr
{
    LogTrace();//{} ??有什么意义? -- 跟踪当前行为 

    // Just in case immutable objects were passed
    //拿到host ,copy防止值被修改
    NSString *host = [inHost copy];
    //interface?接口?
    NSString *interface = [inInterface copy];
    
    //声明两个__block的
    __block BOOL result = NO;
    //error信息
    __block NSError *preConnectErr = nil;
    
    //gcdBlock ,都包裹在自动释放池中 :
    // 1: 大量临时变量 connect : 重连
    // 2: 自定义线程管理 : nsoperation
    // 3: 非UI 命令 工具
    dispatch_block_t block = ^{ @autoreleasepool {
    
        // Check for problems with host parameter
        
        if ([host length] == 0)
        {
            NSString *msg = @"Invalid host parameter (nil or \"\"). Should be a domain name or IP address string.";
            preConnectErr = [self badParamError:msg];
            
            // 其实就是return,大牛的代码真是充满逼格 - ret
            // 异步性 return --> 函数 - 编译
            // 宏定义 -- 预编译 -- return - 提前
            return_from_block;
        }
        
        // Run through standard pre-connect checks
        //一个前置的检查,如果没通过返回,这q个检查里,如果interface有值,则会将本机的IPV4 IPV6的 address设置上。
        // 参数 : 指针 操作同一片内存空间
        if (![self preConnectWithInterface:interface error:&preConnectErr])
        {
            return_from_block;
        }
    
        // We've made it past all the checks.
        // It's time to start the connection process.
        //flags 做或等运算。 flags标识为开始Socket连接
        flags |= kSocketStarted;
        
        //又是一个{}? 只是为了标记么?
        LogVerbose(@"Dispatching DNS lookup...");
        
        // It's possible that the given host parameter is actually a NSMutableString.
        //很可能给我们的服务端的参数是一个可变字符串
        // So we want to copy it now, within this block that will be executed synchronously.
        //所以我们需要copy,在Block里同步的执行
        // This way the asynchronous lookup block below doesn't have to worry about it changing.
        //这种基于Block的异步查找,不需要担心它被改变
    
        //copy,防止改变
        NSString *hostCpy = [host copy];
        
        //拿到状态
        int aStateIndex = stateIndex;
        __weak GCDAsyncSocket *weakSelf = self;
        
        //全局Queue ---> 服务器
        // client  <---> server
        dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //异步执行
        dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
        //忽视循环引用
        #pragma clang diagnostic push
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
        
        //查找错误
        NSError *lookupErr = nil;
        //server地址数组(包含IPV4 IPV6的地址  sockaddr_in6、sockaddr_in类型)
        NSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];
        
        //strongSelf
        __strong GCDAsyncSocket *strongSelf = weakSelf;
        
        //完整Block安全形态,在加个if
        if (strongSelf == nil) return_from_block;
        
        //如果有错
        if (lookupErr)
        {
            //用cocketQueue
            dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
                //一些错误处理,清空一些数据等等
                [strongSelf lookup:aStateIndex didFail:lookupErr];
            }});
        }
        //正常
        else
        {
        
            NSData *address4 = nil;
            NSData *address6 = nil;
            //遍历地址数组
            for (NSData *address in addresses)
            {
                //判断address4为空,且address为IPV4
                if (!address4 && [[self class] isIPv4Address:address])
                {
                    address4 = address;
                }
                //判断address6为空,且address为IPV6
                else if (!address6 && [[self class] isIPv6Address:address])
                {
                    address6 = address;
                }
            }
            //异步去发起连接   串行队列
            dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
            
                [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
            }});
        }
        
        #pragma clang diagnostic pop
        }});
        
        
        //开启连接超时
        [self startConnectTimeout:timeout];
        
        result = YES;
    }};
    //在socketQueue中执行这个Block
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
        block();
        //否则同步的调起这个queue去执行
    else
        dispatch_sync(socketQueue, block);
    
    //如果有错误,赋值错误
    if (errPtr) *errPtr = preConnectErr;
    //把连接是否成功的result返回
    return result;
}

拆分下函数,LogTrace()这个宏分两种情况

// 调试状态下
#define LogTrace()              LogObjc(LOG_FLAG_VERBOSE, @"%@: %@", THIS_FILE, THIS_METHOD)
// 非调试状态
#define LogTrace()              {}

如果把block里面的代码折叠起来就会发现其实很简单,所以我们接下来的重点就分析下block里面的代码

dispatch_block_t block = ^{ @autoreleasepool {
    
    // Check for problems with host parameter
    
    if ([host length] == 0)
    {
        NSString *msg = @"Invalid host parameter (nil or \"\"). Should be a domain name or IP address string.";
        preConnectErr = [self badParamError:msg];
        
        // 异步性 return --> 函数 - 编译
        // 宏定义 -- 预编译 -- return - 提前
        return_from_block;
    }
    
    // Run through standard pre-connect checks
    //一个前置的检查,如果没通过返回,这q个检查里,如果interface有值,则会将本机的IPV4 IPV6的 address设置上。
    // 参数 : 指针 操作同一片内存空间
    if (![self preConnectWithInterface:interface error:&preConnectErr])
    {
        return_from_block;
    }
    
    // We've made it past all the checks.
    // It's time to start the connection process.
    //flags 做或等运算。 flags标识为开始Socket连接
    flags |= kSocketStarted;
    
    //又是一个{}? 只是为了标记么?
    LogVerbose(@"Dispatching DNS lookup...");
    
    // It's possible that the given host parameter is actually a NSMutableString.
    //很可能给我们的服务端的参数是一个可变字符串
    // So we want to copy it now, within this block that will be executed synchronously.
    //所以我们需要copy,在Block里同步的执行
    // This way the asynchronous lookup block below doesn't have to worry about it changing.
    //这种基于Block的异步查找,不需要担心它被改变
    
    //copy,防止改变
    NSString *hostCpy = [host copy];
    
    //拿到状态
    int aStateIndex = stateIndex;
    __weak GCDAsyncSocket *weakSelf = self;
    
    //全局Queue ---> 服务器
    // client  <---> server
    dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //异步执行
    dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
        //忽视循环引用
        #pragma clang diagnostic push
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
        
        //查找错误
        NSError *lookupErr = nil;
        //server地址数组(包含IPV4 IPV6的地址  sockaddr_in6、sockaddr_in类型)
        NSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];
        
        //strongSelf
        __strong GCDAsyncSocket *strongSelf = weakSelf;
        
        //完整Block安全形态,在加个if
        if (strongSelf == nil) return_from_block;
        
        //如果有错
        if (lookupErr)
        {
            //用cocketQueue
            dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
                //一些错误处理,清空一些数据等等
                [strongSelf lookup:aStateIndex didFail:lookupErr];
            }});
        }
        //正常
        else
        {
        
            NSData *address4 = nil;
            NSData *address6 = nil;
            //遍历地址数组
            for (NSData *address in addresses)
            {
                //判断address4为空,且address为IPV4
                if (!address4 && [[self class] isIPv4Address:address])
                {
                    address4 = address;
                }
                //判断address6为空,且address为IPV6
                else if (!address6 && [[self class] isIPv6Address:address])
                {
                    address6 = address;
                }
            }
            //异步去发起连接   串行队列
            dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
            
            [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
            }});
        }
    
    #pragma clang diagnostic pop
    }});
    
    
    //开启连接超时
    [self startConnectTimeout:timeout];
    
    result = YES;
}};

return_from_block宏定义,大牛为什么这里要定义一个新的宏去表示return,因为这样定义的话可以在预编译的时候就把return给编译进去,就不会出现block要退出的时候还没编译出来就过了,不过这样的情况比较少

/**
 * Seeing a return statements within an inner block
 * can sometimes be mistaken for a return point of the enclosing method.
 * This makes inline blocks a bit easier to read.
**/
#define return_from_block  return

preConnectWithInterface: error:函数的作用:前置检查,检测interface是否有值,有就赋值

//在连接之前的接口检查,一般我们传nil  interface本机的IP 端口等等
- (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr
{
    // socket - connect
    //先断言,如果当前的queue不是初始化quueue,直接报错
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //无代理
    if (delegate == nil) // Must have delegate set
    {
        if (errPtr)
        {
            NSString *msg = @"Attempting to connect without a delegate. Set a delegate first.";
            *errPtr = [self badConfigError:msg];
        }
        return NO;
    }
    //没有代理queue
    if (delegateQueue == NULL) // Must have delegate queue set
    {
        if (errPtr)
        {
            NSString *msg = @"Attempting to connect without a delegate queue. Set a delegate queue first.";
            *errPtr = [self badConfigError:msg];
        }
        return NO;
    }
    
    //当前不是非连接状态
    if (![self isDisconnected]) // Must be disconnected
    {
        if (errPtr)
        {
            NSString *msg = @"Attempting to connect while connected or accepting connections. Disconnect first.";
            *errPtr = [self badConfigError:msg];
        }
        return NO;
    }
    
    //判断是否支持IPV4 IPV6  &位与运算,因为枚举是用  左位移<<运算定义的,所以可以用来判断 config包不包含某个枚举。因为一个值可能包含好几个枚举值,所以这时候不能用==来判断,只能用&来判断
    BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
    BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
    
    //是否都不支持
    if (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled
    {
        if (errPtr)
        {
            NSString *msg = @"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.";
            *errPtr = [self badConfigError:msg];
        }
        return NO;
    }
    
    //如果有interface,本机地址
    if (interface)
    {
        NSMutableData *interface4 = nil;
        NSMutableData *interface6 = nil;
        
        //得到本机的IPV4 IPV6地址
        [self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:0];
        
        //如果两者都为nil
        if ((interface4 == nil) && (interface6 == nil))
        {
            if (errPtr)
            {
                NSString *msg = @"Unknown interface. Specify valid interface by name (e.g. \"en1\") or IP address.";
                *errPtr = [self badParamError:msg];
            }
            return NO;
        }
        
        if (isIPv4Disabled && (interface6 == nil))
        {
            if (errPtr)
            {
                NSString *msg = @"IPv4 has been disabled and specified interface doesn't support IPv6.";
                *errPtr = [self badParamError:msg];
            }
            return NO;
        }
        
        if (isIPv6Disabled && (interface4 == nil))
        {
            if (errPtr)
            {
                NSString *msg = @"IPv6 has been disabled and specified interface doesn't support IPv4.";
                *errPtr = [self badParamError:msg];
            }
            return NO;
        }
        //如果都没问题,则赋值
        connectInterface4 = interface4;
        connectInterface6 = interface6;
    
    }
    
    // Clear queues (spurious read/write requests post disconnect)
    //清除queue(假的读写请求 ,提交断开连接)
    //读写Queue清除
    [readQueue removeAllObjects];
    [writeQueue removeAllObjects];
    
    return YES;
}

检测完之后获取全局并发队列异步去创建一个线程,lookupHost:port:error:函数去获取服务器地址,通过递归的方式

//全局Queue ---> 服务器
// client  <---> server
dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//异步执行
dispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {
    //忽视循环引用
    #pragma clang diagnostic push
    #pragma clang diagnostic warning "-Wimplicit-retain-self"
    
    //查找错误
    NSError *lookupErr = nil;
    //server地址数组(包含IPV4 IPV6的地址  sockaddr_in6、sockaddr_in类型)
    NSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];
    
    //strongSelf
    __strong GCDAsyncSocket *strongSelf = weakSelf;
    
    //完整Block安全形态,在加个if
    if (strongSelf == nil) return_from_block;
    
    //如果有错
    if (lookupErr)
    {
        //用cocketQueue
        dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
            //一些错误处理,清空一些数据等等
            [strongSelf lookup:aStateIndex didFail:lookupErr];
        }});
    }
    //正常
    else
    {
    
        NSData *address4 = nil;
        NSData *address6 = nil;
        //遍历地址数组
        for (NSData *address in addresses)
        {
            //判断address4为空,且address为IPV4
            if (!address4 && [[self class] isIPv4Address:address])
            {
                address4 = address;
            }
            //判断address6为空,且address为IPV6
            else if (!address6 && [[self class] isIPv6Address:address])
            {
                address6 = address;
            }
        }
        //异步去发起连接   串行队列
        dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
        
            [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
        }});
    }

#pragma clang diagnostic pop
}});

判断一下拿回来的地址是否有错,没错的话赋值到成员变量里面

//如果有错
if (lookupErr)
{
    //用cocketQueue
    dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
    //一些错误处理,清空一些数据等等
        [strongSelf lookup:aStateIndex didFail:lookupErr];
    }});
}
//正常
else
{

    NSData *address4 = nil;
    NSData *address6 = nil;
    //遍历地址数组
    for (NSData *address in addresses)
    {
        //判断address4为空,且address为IPV4
        if (!address4 && [[self class] isIPv4Address:address])
        {
            address4 = address;
        }
        //判断address6为空,且address为IPV6
        else if (!address6 && [[self class] isIPv6Address:address])
        {
            address6 = address;
        }
    }
    //异步去发起连接   串行队列
    dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
        [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
    }});
}

异步串行队列去连接

//异步去发起连接   串行队列
dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
    [strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];
}});

一系列的错误判断之后再去连接

- (void)lookup:(int)aStateIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    //至少有一个server地址
    NSAssert(address4 || address6, @"Expected at least one valid address");
    
    //如果状态不一致,说明断开连接
    if (aStateIndex != stateIndex)
    {
        LogInfo(@"Ignoring lookupDidSucceed, already disconnected");
        
        // The connect operation has been cancelled.
        // That is, socket was disconnected, or connection has already timed out.
        return;
    }
    
    // Check for problems
    //分开判断。
    BOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;
    BOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;
    
    if (isIPv4Disabled && (address6 == nil))
    {
        NSString *msg = @"IPv4 has been disabled and DNS lookup found no IPv6 address.";
        
        [self closeWithError:[self otherError:msg]];
        return;
    }
    
    if (isIPv6Disabled && (address4 == nil))
    {
        NSString *msg = @"IPv6 has been disabled and DNS lookup found no IPv4 address.";
        
        [self closeWithError:[self otherError:msg]];
        return;
    }
    
    // Start the normal connection process
    
    NSError *err = nil;
    //调用连接方法,如果失败,则错误返回
    if (![self connectWithAddress4:address4 address6:address6 error:&err])
    {
        [self closeWithError:err];
    }
}

connectWithAddress4: address6: error:函数是连接socket的入口,主要的功能是做一些连接前的判断

- (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //输出一些东西?
    LogVerbose(@"IPv4: %@:%hu", [[self class] hostFromAddress:address4], [[self class] portFromAddress:address4]);
    LogVerbose(@"IPv6: %@:%hu", [[self class] hostFromAddress:address6], [[self class] portFromAddress:address6]);
    
    // Determine socket type
    
    //判断是否倾向于IPV6
    BOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;
    
    // Create and bind the sockets
    
    //如果有IPV4地址,创建IPV4 Socket
    if (address4)
    {
        LogVerbose(@"Creating IPv4 socket");
        
        socket4FD = [self createSocket:AF_INET connectInterface:connectInterface4 errPtr:errPtr];
    }
    //如果有IPV6地址,创建IPV6 Socket
    if (address6)
    {
        LogVerbose(@"Creating IPv6 socket");
        
        socket6FD = [self createSocket:AF_INET6 connectInterface:connectInterface6 errPtr:errPtr];
    }
    
    //如果都为空,直接返回
    if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL)
    {
        return NO;
    }
    
    //主选socketFD,备选alternateSocketFD
    int socketFD, alternateSocketFD;
    //主选地址和备选地址
    NSData *address, *alternateAddress;
    
    //IPV6
    if ((preferIPv6 && socket6FD) || socket4FD == SOCKET_NULL)
    {
        socketFD = socket6FD;
        alternateSocketFD = socket4FD;
        address = address6;
        alternateAddress = address4;
    }
    //主选IPV4
    else
    {
        socketFD = socket4FD;
        alternateSocketFD = socket6FD;
        address = address4;
        alternateAddress = address6;
    }
    //拿到当前状态
    int aStateIndex = stateIndex;
    //用socket和address去连接
    // socket & connect
    [self connectSocket:socketFD address:address stateIndex:aStateIndex];
    
    //如果有备选地址
    if (alternateAddress)
    {
        //延迟去连接备选的地址
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), socketQueue, ^{
            [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex];
        });
    }
    
    return YES;
    }

createSocket: connectInterface: errPtr:函数主要是创建一个socket

//创建Socket
- (int)createSocket:(int)family connectInterface:(NSData *)connectInterface errPtr:(NSError **)errPtr
{
    //创建socket,用的SOCK_STREAM TCP流
    int socketFD = socket(family, SOCK_STREAM, 0);
    //如果创建失败
    if (socketFD == SOCKET_NULL)
    {
        if (errPtr)
        *errPtr = [self errnoErrorWithReason:@"Error in socket() function"];
        
        return socketFD;
    }
    
    //和connectInterface绑定
    if (![self bindSocket:socketFD toInterface:connectInterface error:errPtr])
    {
        //绑定失败,直接关闭返回
        [self closeSocket:socketFD];
        
        return SOCKET_NULL;
    }
    
    // Prevent SIGPIPE signals
    //防止终止进程的信号?
    int nosigpipe = 1;
    //SO_NOSIGPIPE是为了避免网络错误,而导致进程退出。用这个来避免系统发送signal
    setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
    
    return socketFD;
}

connectSocket:address:stateIndex:函数创建一个全局并发队列去调用connect()函数去连接

//连接最终方法 3 finnal。。。
- (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aStateIndex
{
    // If there already is a socket connected, we close socketFD and return
    //已连接,关闭连接返回
    if (self.isConnected)
    {
        [self closeSocket:socketFD];
        return;
    }
    
    // Start the connection process in a background queue
    //开始连接过程,在后台queue中
    __weak GCDAsyncSocket *weakSelf = self;
    
    //获取到全局Queue
    dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //新线程
    dispatch_async(globalConcurrentQueue, ^{
    #pragma clang diagnostic push
    #pragma clang diagnostic warning "-Wimplicit-retain-self"
        //调用connect方法,该函数阻塞线程,所以要异步新线程
        //客户端向特定网络地址的服务器发送连接请求,连接成功返回0,失败返回 -1。
        int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]);
        
        //老样子,安全判断
        __strong GCDAsyncSocket *strongSelf = weakSelf;
        if (strongSelf == nil) return_from_block;
        
        //在socketQueue中,开辟线程
        dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {
            //如果状态为已经连接,关闭连接返回
            if (strongSelf.isConnected)
            {
                [strongSelf closeSocket:socketFD];
                return_from_block;
            }
            
            //说明连接成功
            if (result == 0)
            {
                //关闭掉另一个没用的socket
                [self closeUnusedSocket:socketFD];
                //调用didConnect,生成stream,改变状态等等!
                [strongSelf didConnect:aStateIndex];
            }
            //连接失败
            else
            {
                //关闭当前socket
                [strongSelf closeSocket:socketFD];
                
                // If there are no more sockets trying to connect, we inform the error to the delegate
                //返回连接错误的error
                if (strongSelf.socket4FD == SOCKET_NULL && strongSelf.socket6FD == SOCKET_NULL)
                {
                    NSError *error = [strongSelf errnoErrorWithReason:@"Error in connect() function"];
                    [strongSelf didNotConnect:aStateIndex error:error];
                }
            }
        }});
    
#pragma clang diagnostic pop
    });
    //输出正在连接中
    LogVerbose(@"Connecting...");
}

如果连接成功,则改变当前socket的状态,调用didConnect:方法

//连接成功后调用,设置一些连接成功的状态
- (void)didConnect:(int)aStateIndex
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //状态不同
    if (aStateIndex != stateIndex)
    {
        LogInfo(@"Ignoring didConnect, already disconnected");
        
        // The connect operation has been cancelled.
        // That is, socket was disconnected, or connection has already timed out.
        return;
    }
    
    //kConnected合并到当前flag中
    flags |= kConnected;
    //停止连接超时
    [self endConnectTimeout];
    
#if TARGET_OS_IPHONE
    // The endConnectTimeout method executed above incremented the stateIndex.
    //上面的endConnectTimeout,会导致stateIndex增加,所以需要重新赋值
    aStateIndex = stateIndex;
#endif
    
    // Setup read/write streams (as workaround for specific shortcomings in the iOS platform)
    // 
    // Note:
    // There may be configuration options that must be set by the delegate before opening the streams.
    //打开stream之前必须用相关配置设置代理
    // The primary example is the kCFStreamNetworkServiceTypeVoIP flag, which only works on an unopened stream.
    //主要的例子是kCFStreamNetworkServiceTypeVoIP标记,只能工作在未打开的stream中?
    // 
    // Thus we wait until after the socket:didConnectToHost:port: delegate method has completed.
    //所以我们要等待,连接完成的代理调用完
    // This gives the delegate time to properly configure the streams if needed.
    //这些给了代理时间,去正确的配置Stream,如果是必要的话
    
    //创建个Block来初始化Stream
    dispatch_block_t SetupStreamsPart1 = ^{
    
    NSLog(@"hello~");
#if TARGET_OS_IPHONE
    //创建读写stream失败,则关闭并报对应错误
    if (![self createReadAndWriteStream])
    {
        [self closeWithError:[self otherError:@"Error creating CFStreams"]];
        return;
    }
    
    //参数是给NO的,就是有可读bytes的时候,不会调用回调函数
    if (![self registerForStreamCallbacksIncludingReadWrite:NO])
    {
        [self closeWithError:[self otherError:@"Error in CFStreamSetClient"]];
        return;
    }
    
#endif
    };
    //part2设置stream
    dispatch_block_t SetupStreamsPart2 = ^{
#if TARGET_OS_IPHONE
        //状态不一样直接返回
        if (aStateIndex != stateIndex)
        {
            // The socket has been disconnected.
            return;
        }
        //如果加到runloop上失败
        if (![self addStreamsToRunLoop])
        {
            //错误返回
            [self closeWithError:[self otherError:@"Error in CFStreamScheduleWithRunLoop"]];
            return;
        }
        
        //读写stream open
        if (![self openStreams])
        {
            //开启错误返回
            [self closeWithError:[self otherError:@"Error creating CFStreams"]];
            return;
        }
    
#endif
    };
    
    // Notify delegate
    //通知代理
    //拿到server端的host port
    NSString *host = [self connectedHost];
    uint16_t port = [self connectedPort];
    //拿到unix域的 url
    NSURL *url = [self connectedUrl];
    //拿到代理
    __strong id theDelegate = delegate;
    
    //代理队列 和 Host不为nil 且响应didConnectToHost代理方法
    if (delegateQueue && host != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)])
    {
        //调用初始化stream1
        SetupStreamsPart1();
        
        dispatch_async(delegateQueue, ^{ @autoreleasepool {
        
            //到代理队列调用连接成功的代理方法
            [theDelegate socket:self didConnectToHost:host port:port];
            
            //然后回到socketQueue中去执行初始化stream2
            dispatch_async(socketQueue, ^{ @autoreleasepool {
            
            SetupStreamsPart2();
            }});
        }});
    }
    //这个是unix domain 请求回调
    else if (delegateQueue && url != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToUrl:)])
    {
        SetupStreamsPart1();
        
        dispatch_async(delegateQueue, ^{ @autoreleasepool {
        
            [theDelegate socket:self didConnectToUrl:url];
            
            dispatch_async(socketQueue, ^{ @autoreleasepool {
            
            SetupStreamsPart2();
            }});
        }});
    }
    //否则只初始化stream
    else
    {
        SetupStreamsPart1();
        SetupStreamsPart2();
    }
    
    // Get the connected socket
    
    int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
    
    //fcntl,功能描述:根据文件描述词来操作文件的特性。http://blog.csdn.net/pbymw8iwm/article/details/7974789
    // Enable non-blocking IO on the socket
    //使socket支持非阻塞IO
    int result = fcntl(socketFD, F_SETFL, O_NONBLOCK);
    if (result == -1)
    {
        //失败 ,报错
        NSString *errMsg = @"Error enabling non-blocking IO on socket (fcntl)";
        [self closeWithError:[self otherError:errMsg]];
        
        return;
    }
    
    // Setup our read/write sources
    //初始化读写source
    [self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];
    
    // Dequeue any pending read/write requests
    //开始下一个任务
    [self maybeDequeueRead];
    [self maybeDequeueWrite];
}

这个方法主要做了下面几件事:

  • 把当前状态flags加上已连接,并且关闭掉我们一开始连接开启的,连接超时的定时器
//kConnected合并到当前flag中
flags |= kConnected;
//停止连接超时
[self endConnectTimeout];
  • 初始化了两个Block:SetupStreamsPart1SetupStreamsPart2,这两个Block做的事都和读写流有关。SetupStreamsPart1用来创建读写流,并且注册回调。另一个SetupStreamsPart2用来把流添加到当前线程的runloop上,并且打开流。
//创建个Block来初始化Stream
dispatch_block_t SetupStreamsPart1 = ^{
    ...
};
//part2设置stream
dispatch_block_t SetupStreamsPart2 = ^{
    ...
};
  • 判断是否有代理queuehost或者url这些参数是否为空、是否代理响应didConnectToHostdidConnectToUrl代理,这两种分别对应了普通socket连接和unix domin socket连接。如果实现了对应的代理,则调用连接成功的代理。
//代理队列 和 Host不为nil 且响应didConnectToHost代理方法
if (delegateQueue && host != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)])
{
    ...
}
//这个是unix domain 请求回调
else if (delegateQueue && url != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToUrl:)])
{
    ...
}
//否则只初始化stream
else
{
    ...
}
  • 在调用代理的同时,调用了我们之前初始化的两个读写流相关的Block。
//调用初始化stream1
SetupStreamsPart1();

dispatch_async(delegateQueue, ^{ @autoreleasepool {

    //到代理队列调用连接成功的代理方法
    [theDelegate socket:self didConnectToHost:host port:port];

    //然后回到socketQueue中去执行初始化stream2
    dispatch_async(socketQueue, ^{ @autoreleasepool {
        SetupStreamsPart2();
    }});
}});
  • 使socket支持非阻塞IO,默认是阻塞IO的
//使socket支持非阻塞IO
int result = fcntl(socketFD, F_SETFL, O_NONBLOCK);
  • 初始化读写source
[self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];

block(SetupStreamsPart1)里面的代码createReadAndWriteStream()函数:创建读写stream

//创建读写stream
- (BOOL)createReadAndWriteStream
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //如果有一个有值,就返回
    if (readStream || writeStream)
    {
        // Streams already created
        return YES;
    }
    //拿到socket,首选是socket4FD,其次socket6FD,都没有才是socketUN,socketUN应该是Unix的socket结构体
    int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
    
    //如果都为空,返回NO
    if (socketFD == SOCKET_NULL)
    {
        // Cannot create streams without a file descriptor
        return NO;
    }
    
    //如果非连接,返回NO
    if (![self isConnected])
    {
        // Cannot create streams until file descriptor is connected
        return NO;
    }
    
    LogVerbose(@"Creating read and write stream...");
    
#pragma mark - 绑定Socket和CFStream
    //下面的接口用于创建一对 socket stream,一个用于读取,一个用于写入:
    CFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socketFD, &readStream, &writeStream);
    
    // The kCFStreamPropertyShouldCloseNativeSocket property should be false by default (for our case).
    // But let`s not take any chances.
    
    
    
    //读写stream都设置成不会随着绑定的socket一起close,release。 kCFBooleanFalse不一起,kCFBooleanTrue一起
    if (readStream)
        CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
    if (writeStream)
        CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
    
    //如果有一个为空
    if ((readStream == NULL) || (writeStream == NULL))
    {
        LogWarn(@"Unable to create read and write stream...");
        
        //关闭对应的stream
        if (readStream)
        {
            CFReadStreamClose(readStream);
            CFRelease(readStream);
            readStream = NULL;
        }
        if (writeStream)
        {
            CFWriteStreamClose(writeStream);
            CFRelease(writeStream);
            writeStream = NULL;
        }
        //返回创建失败
        return NO;
    }
    //创建成功
    return YES;
}

block(SetupStreamsPart1)里面的代码registerForStreamCallbacksIncludingReadWrite()函数:注册stream

//注册Stream的回调
- (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite
{
    LogVerbose(@"%@ %@", THIS_METHOD, (includeReadWrite ? @"YES" : @"NO"));
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    //判断读写stream是不是都为空
    NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
    
    //客户端stream上下文对象
    streamContext.version = 0;
    streamContext.info = (__bridge void *)(self);
    streamContext.retain = nil;
    streamContext.release = nil;
    streamContext.copyDescription = nil;
    
    //    The open has completed successfully.
    //    The stream has bytes to be read.
    //    The stream can accept bytes for writing.
    //        An error has occurred on the stream.
    //        The end of the stream has been reached.
    
    //设置一个CF的flag  两种,一种是错误发生的时候,一种是stream事件结束
    CFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered ;
    //如果包含读写
    if (includeReadWrite)
    //仍然有Bytes要读的时候     The stream has bytes to be read.
    readStreamEvents |= kCFStreamEventHasBytesAvailable;
    
    //给读stream设置客户端,会在之前设置的那些标记下回调函数 CFReadStreamCallback。设置失败的话直接返回NO
    if (!CFReadStreamSetClient(readStream, readStreamEvents, &CFReadStreamCallback, &streamContext))
    {
        return NO;
    }
    
    //写的flag,也一样
    CFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
    if (includeReadWrite)
    writeStreamEvents |= kCFStreamEventCanAcceptBytes;
    
    if (!CFWriteStreamSetClient(writeStream, writeStreamEvents, &CFWriteStreamCallback, &streamContext))
    {
        return NO;
    }
    //走到最后说明读写都设置回调成功,返回YES
    return YES;
}

block(SetupStreamsPart2)里面的代码addStreamsToRunLoop函数:把stream添加到runloop上

//把stream添加到runloop上
- (BOOL)addStreamsToRunLoop
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
    
    //判断flag里是否包含kAddedStreamsToRunLoop,没添加过则添加。
    if (!(flags & kAddedStreamsToRunLoop))
    {
        LogVerbose(@"Adding streams to runloop...");
        
        
        [[self class] startCFStreamThreadIfNeeded];
        //在开启的线程中去执行,阻塞式的
        [[self class] performSelector:@selector(scheduleCFStreams:)
                     onThread:cfstreamThread
                   withObject:self
                waitUntilDone:YES];
        
        //添加标识
        flags |= kAddedStreamsToRunLoop;
    }
    
    return YES;
}

block(SetupStreamsPart2)里面的代码openStreams函数:打开stream

//打开stream
- (BOOL)openStreams
{
    LogTrace();
    
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    //断言读写stream都不会空
    NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null");
    
    //返回stream的状态
    /*
    kCFStreamStatusNotOpen = 0,
    kCFStreamStatusOpening,  // open is in-progress
    kCFStreamStatusOpen,
    kCFStreamStatusReading,
    kCFStreamStatusWriting,
    kCFStreamStatusAtEnd,    // no further bytes can be read/written
    kCFStreamStatusClosed,
    kCFStreamStatusError
    */
    CFStreamStatus readStatus = CFReadStreamGetStatus(readStream);
    CFStreamStatus writeStatus = CFWriteStreamGetStatus(writeStream);
    
    //如果有任意一个没有开启
    if ((readStatus == kCFStreamStatusNotOpen) || (writeStatus == kCFStreamStatusNotOpen))
    {
        LogVerbose(@"Opening read and write stream...");
        
        //开启 - NSStream 
        BOOL r1 = CFReadStreamOpen(readStream);
        BOOL r2 = CFWriteStreamOpen(writeStream);
        
        //有一个开启失败
        if (!r1 || !r2)
        {
            LogError(@"Error in CFStreamOpen");
            return NO;
        }
    }
    
    return YES;
}

注册stream的回调函数中,先看CFReadStreamCallback,读取到数据的时候会调用doReadData函数

//读stream的回调
static void CFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)
{
    //得到触发回调的sokcet
    GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
    
    switch(type)
    {
        //如果是可读数据的回调
        case kCFStreamEventHasBytesAvailable:
        {
            //在socketQueue中调用
            dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
            
                LogCVerbose(@"CFReadStreamCallback - HasBytesAvailable");
                //如果不是同一个stream,直接返回
                if (asyncSocket->readStream != stream)
                    return_from_block;
                
                //如果包含正在初始化TLS,就先去握手再说
                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
                {
                    // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
                    // (A callback related to the tcp stream, but not to the SSL layer).
                    
                    if (CFReadStreamHasBytesAvailable(asyncSocket->readStream))
                    {
                        asyncSocket->flags |= kSecureSocketHasBytesAvailable;
                        [asyncSocket cf_finishSSLHandshake];
                    }
                }
                //去读取数据
                else
                {
                    asyncSocket->flags |= kSecureSocketHasBytesAvailable;
                    [asyncSocket doReadData];
                }
            }});
            
            break;
        }
        //这是错误的回调
        default:
        {
            //得到错误
            NSError *error = (__bridge_transfer  NSError *)CFReadStreamCopyError(stream);
            
            //到达流尾的错误
            if (error == nil && type == kCFStreamEventEndEncountered)
            {
                error = [asyncSocket connectionClosedError];
            }
            
            dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
            
                LogCVerbose(@"CFReadStreamCallback - Other");
                
                if (asyncSocket->readStream != stream)
                return_from_block;
                
                //如果当前是正在进行SSL认证
                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
                {
                    //则关闭ssl,报错
                    [asyncSocket cf_abortSSLHandshake:error];
                }
                else
                {
                    //直接关闭
                    [asyncSocket closeWithError:error];
                }
            }});
            
            break;
        }
    }
	
}

doReadData函数这里面会处理读取出来的数据,然后把调用completeCurrentRead方法把数据用代理传出去

//读取数据
- (void)doReadData
{
    ...
    if (done)
    {
        //完成这次数据的读取
        [self completeCurrentRead];
        //如果没出错,没有到边界,prebuffer中还有可读数据
        if (!error && (!socketEOF || [preBuffer availableBytes] > 0))
        {
            //让读操作离队,继续进行下一次读取
            [self maybeDequeueRead];
        }
    }
    ...
}
//完成了这次的读数据
- (void)completeCurrentRead
{
    LogTrace();
    //断言currentRead
    NSAssert(currentRead, @"Trying to complete current read when there is no current read.");
    
    //结果数据
    NSData *result = nil;
    
    //如果是我们自己创建的Buffer
    if (currentRead->bufferOwner)
    {
        // We created the buffer on behalf of the user.
        // Trim our buffer to be the proper size.
        //修剪buffer到合适的大小
        //把大小设置到我们读取到的大小
        [currentRead->buffer setLength:currentRead->bytesDone];
        //赋值给result
        result = currentRead->buffer;
    }
    else
    {
        // We did NOT create the buffer.
        // The buffer is owned by the caller.
        // Only trim the buffer if we had to increase its size.
        //这是调用者的data,我们只会去加大尺寸
        if ([currentRead->buffer length] > currentRead->originalBufferLength)
        {
            //拿到的读的size
            NSUInteger readSize = currentRead->startOffset + currentRead->bytesDone;
            //拿到原始尺寸
            NSUInteger origSize = currentRead->originalBufferLength;
            
            //取得最大的
            NSUInteger buffSize = MAX(readSize, origSize);
            //把buffer设置为较大的尺寸
            [currentRead->buffer setLength:buffSize];
        }
        //拿到数据的头指针
        uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset;
        
        //reslut为,从头指针开始到长度为写的长度 freeWhenDone为YES,创建完就释放buffer
        result = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO];
    }
    
    __strong id theDelegate = delegate;
    
    #pragma mark -总算到调用代理方法,接受到数据了
    if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)])
    {
        //拿到当前的数据包
        GCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer
        
        dispatch_async(delegateQueue, ^{ @autoreleasepool {
            //把result在代理queue中回调出去。
            [theDelegate socket:self didReadData:result withTag:theRead->tag];
        }});
    }
    //取消掉读取超时
    [self endCurrentRead];
}

CFWriteStreamCallback中的处理方式和CFReadStreamCallback差不多

//写的回调
static void CFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)
{
    GCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;
    
    switch(type)
    {
    
        //如果可写字节
        case kCFStreamEventCanAcceptBytes:
        {
            dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
            
                    LogCVerbose(@"CFWriteStreamCallback - CanAcceptBytes");
                    
                    if (asyncSocket->writeStream != stream)
                        return_from_block;
                    
                    if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
                    {
                        // If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.
                        // (A callback related to the tcp stream, but not to the SSL layer).
                        
                        //判断当前sokcet是否可以写数据,而不被阻塞
                        if (CFWriteStreamCanAcceptBytes(asyncSocket->writeStream))
                        {
                            asyncSocket->flags |= kSocketCanAcceptBytes;
                            [asyncSocket cf_finishSSLHandshake];
                        }
                    }
                    else
                    {
                        asyncSocket->flags |= kSocketCanAcceptBytes;
                        [asyncSocket doWriteData];
                    }
                }});
            
            break;
        }
        default:
        {
            NSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream);
            
            if (error == nil && type == kCFStreamEventEndEncountered)
            {
                error = [asyncSocket connectionClosedError];
            }
            
            dispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {
            
                LogCVerbose(@"CFWriteStreamCallback - Other");
                
                if (asyncSocket->writeStream != stream)
                    return_from_block;
                
                if ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))
                {
                    [asyncSocket cf_abortSSLHandshake:error];
                }
                else
                {
                    [asyncSocket closeWithError:error];
                }
            }});
        
        break;
        }
    }

}

调用doWriteData函数去执行写入的操作,处理完成后调用completeCurrentWrite把数据回调出去

//开始写数据 ,当前任务的
- (void)doWriteData
{
    ...
    //如果完成了
    if (done)
    {
        //完成操作
        [self completeCurrentWrite];
        
        if (!error)
        {
            dispatch_async(socketQueue, ^{ @autoreleasepool{
                //开始下一次的读取任务
                [self maybeDequeueWrite];
            }});
        }
    }
    ...
}
//完成了当前的写
- (void)completeCurrentWrite
{
    LogTrace();
    
    NSAssert(currentWrite, @"Trying to complete current write when there is no current write.");
    
    
    __strong id theDelegate = delegate;
    
    if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)])
    {
        long theWriteTag = currentWrite->tag;
        
        //调用完成写的回调
        dispatch_async(delegateQueue, ^{ @autoreleasepool {
        
            [theDelegate socket:self didWriteDataWithTag:theWriteTag];
        }});
    }
    
    //关闭当前写
    [self endCurrentWrite];
}

参考文章

iOS即时通讯进阶 - CocoaAsyncSocket源码解析(Connect篇)
iOS即时通讯进阶 - CocoaAsyncSocket源码解析(Connect篇终)
iOS即时通讯进阶 - CocoaAsyncSocket源码解析(Read篇)
iOS即时通讯进阶 - CocoaAsyncSocket源码解析(Read篇终)