iOS GCDAsyncSocket源码分析(二)

由于上一篇文章篇幅过长移到这边。

3.read&write
  • 先看write
//写数据对外方法
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
    if ([data length] == 0) return;
    
    //初始化写包,可知write操作是用GCDAsyncWritePacket这种包的形式发送的,如果没错的话,read应该也是这样吧。
    GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];
    //异步
    dispatch_async(socketQueue, ^{ @autoreleasepool {
        
        LogTrace();
        
        if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))
        {
            //writeQueue是一个数组,把当前packet添加进去
            [writeQueue addObject:packet];
            //还没看到write(),得继续跳转
            [self maybeDequeueWrite];
        }
    }});
    
    // Do not rely on the block being run in order to release the packet,
    // as the queue might get released without the block completing.
}

这个方法只是构建了一个GCDAsyncWritePacket包,添加到writequeue数组中,然后继续调用别的方法

- (void)maybeDequeueWrite
{
    LogTrace();
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    
    // If we're not currently processing a write AND we have an available write stream
    //currentWrite也是一个GCDAsyncWritePacket包
    //如果currentWrite为空,且socket已经连接
    if ((currentWrite == nil) && (flags & kConnected))
    {
        //如果用来写的数组数量大于0
        if ([writeQueue count] > 0)
        {
            // Dequeue the next object in the write queue
            //将第一个包赋值给currentWrite,并从数组中移除
            currentWrite = [writeQueue objectAtIndex:0];
            [writeQueue removeObjectAtIndex:0];
            
            //TLS,如果是GCDAsyncSpecialPacket,一般不走这里
            if ([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]])
            {
                LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
                
                // Attempt to start TLS
                flags |= kStartingWriteTLS;
                
                // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
                [self maybeStartTLS];
            }
            else
            {
                LogVerbose(@"Dequeued GCDAsyncWritePacket");
                
                // Setup write timer (if needed)
                //设置一个GCD timer 来记录超时时间
                [self setupWriteTimerWithTimeout:currentWrite->timeout];
                
                // 开始write
                [self doWriteData];
            }
        }
        // flags & kDisconnectAfterWrites 跟 数组小于等于0 的 意思差不多
        else if (flags & kDisconnectAfterWrites)
        {
            //如果没有可读任务,直接关闭socket
            if (flags & kDisconnectAfterReads)
            {
                if (([readQueue count] == 0) && (currentRead == nil))
                {
                    [self closeWithError:nil];
                }
            }
            else
            {
                [self closeWithError:nil];
            }
        }
    }
}

这个方法主要的就是给currentWrite赋值,writeQueue的数量判断,大于0就继续往下,小于等于0就断开连接。还做了一步[GCDAsyncSpecialPacket class]的判断,我们write的时候,进来的是普通包,不是special包,基本上不会走进去,所以我那继续往下走就是执行[self doWriteData];这又是一个很长的方法。这里面包含了很多flags判断操作,比如:socket安全等等,需要有设置才会执行

- (void)doWriteData
{
    LogTrace();
    //currentWrite为空,不写
    if ((currentWrite == nil) || (flags & kWritesPaused))
    {
        LogVerbose(@"No currentWrite or kWritesPaused");
    
        if ([self usingCFStreamForTLS])
        {
            //啥也不干
        }
        else
        {
            //如果socket中可接受写数据,防止反复触发写source,挂起
            if (flags & kSocketCanAcceptBytes)
            {
                [self suspendWriteSource];
            }
        }
        return;
    }
    
    //如果当前socket无法在写数据了
    if (!(flags & kSocketCanAcceptBytes))
    {
        LogVerbose(@"No space available to write...");
        
        // No space available to write.
        
        //如果不是cfstream
        if (![self usingCFStreamForTLS])
        {
            // Need to wait for writeSource to fire and notify us of
            // available space in the socket's internal write buffer.
            //则恢复写source,当有空间去写的时候,会触发回来
            [self resumeWriteSource];
        }
        return;
    }
    
    //如果正在进行TLS认证,就是那个specialpacket,我们当前不是这个所以先跳过
    if (flags & kStartingWriteTLS)
    {
        LogVerbose(@"Waiting for SSL/TLS handshake to complete");
        
        // The writeQueue is waiting for SSL/TLS handshake to complete.
        
        if (flags & kStartingReadTLS)
        {
            //如果是安全通道,并且I/O阻塞,那么重新去握手
            if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
            {
                // We are in the process of a SSL Handshake.
                // We were waiting for available space in the socket's internal OS buffer to continue writing.
            
                [self ssl_continueSSLHandshake];
            }
        }
        //说明不走`TLS`了,因为只支持写的TLS
        else
        {
            // We are still waiting for the readQueue to drain and start the SSL/TLS process.
            // We now know we can write to the socket.
            
            //挂起写source
            if (![self usingCFStreamForTLS])
            {
                // Suspend the write source or else it will continue to fire nonstop.
                [self suspendWriteSource];
            }
        }
        
        return;
    }
    
    // Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet)
    
    //开始写数据
    
    BOOL waiting = NO;
    NSError *error = nil;
    size_t bytesWritten = 0;
    
    //安全连接
    if (flags & kSocketSecure)
    {
           //这里先省略,关键看普通连接。有需要仔细了解的可以私信我。我给你发代码- -
           ...
    } 
    //普通socket
    else
    {
        //拿到当前socket
        int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
        //得到指针偏移
        const uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;
        // 要写的数据大小
        NSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;
        
        if (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)
        {
            bytesToWrite = SIZE_MAX;
        }
        //直接写,熟悉的write()
        ssize_t result = write(socketFD, buffer, (size_t)bytesToWrite);
        LogVerbose(@"wrote to socket = %zd", result);
        
        // 结果判断
        if (result < 0)
        {
            //IO阻塞
            if (errno == EWOULDBLOCK)
            {
                waiting = YES;
            }
            else
            {
                error = [self errnoErrorWithReason:@"Error in write() function"];
            }
        }
        else
        {
            //得到写的大小
            bytesWritten = result;
        }
    }
    
    //注意,如果用CFStream,很可能会被恶意的放置数据 阻塞socket
    
    //如果等待,则恢复写source
    if (waiting)
    {
        //把socket可接受数据的标记去掉
        flags &= ~kSocketCanAcceptBytes;
        
        if (![self usingCFStreamForTLS])
        {
            //恢复写source
            [self resumeWriteSource];
        }
    }
    
    // Check our results
    
    //判断是否完成
    BOOL done = NO;
    //判断已写大小
    if (bytesWritten > 0)
    {
        // Update total amount read for the current write
        //更新当前总共写的大小
        currentWrite->bytesDone += bytesWritten;
        LogVerbose(@"currentWrite->bytesDone = %lu", (unsigned long)currentWrite->bytesDone);
        
        // Is packet done?
        //判断当前写包是否写完
        done = (currentWrite->bytesDone == [currentWrite->buffer length]);
    }
    
    //如果完成了
    if (done)
    {
        //完成操作,回调发送成功代理事件,注意,代理回调是这里
        [self completeCurrentWrite];
        
        if (!error)
        {
            dispatch_async(socketQueue, ^{ @autoreleasepool{
                //开始下一次的读取任务
                [self maybeDequeueWrite];
            }});
        }
    }
    //未完成
    else
    {
        //如果不是等待 而且没有出错
        if (!waiting && !error)
        {
            //这是我们写了一部分数据的情况。
            
            //去掉可接受数据的标记
            flags &= ~kSocketCanAcceptBytes;
            //再去等读source触发
            if (![self usingCFStreamForTLS])
            {
                [self resumeWriteSource];
            }
        }
        
        //如果已写大于0
        if (bytesWritten > 0)
        {
            __strong id theDelegate = delegate;

            //调用写的进度代理
            if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])
            {
                long theWriteTag = currentWrite->tag;
                
                dispatch_async(delegateQueue, ^{ @autoreleasepool {
                    
                    [theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag];
                }});
            }
        }
    }
    
    // Check for errors
    //如果有错,则报错断开连接
    if (error)
    {
        [self closeWithError:[self errnoErrorWithReason:@"Error in write() function"]];
    }
}

这个方法贼长,长的主要原因还是TSL,SSL这两个安全传输协议的处理,我们这里就先看看普通的吧...那些实在很长,注释也很多。
接下来看read,看看会发现,方法格式差不多

  • read
- (void)readDataWithTimeout:(NSTimeInterval)timeout
                     buffer:(NSMutableData *)buffer
               bufferOffset:(NSUInteger)offset
                  maxLength:(NSUInteger)length
                        tag:(long)tag
{
    if (offset > [buffer length]) {
        LogWarn(@"Cannot read: offset > [buffer length]");
        return;
    }
    
    GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer
                                                              startOffset:offset
                                                                maxLength:length
                                                                  timeout:timeout
                                                               readLength:0
                                                               terminator:nil
                                                                      tag:tag];
    
    dispatch_async(socketQueue, ^{ @autoreleasepool {
        
        LogTrace();
        
        if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))
        {
            //往读的队列添加任务,任务是包的形式
            [readQueue addObject:packet];
            [self maybeDequeueRead];
        }
    }});
}

同样是构造一个GCDAsyncReadPacket包,然后添加到数组中,然后执行下一个方法

- (void)maybeDequeueRead
{
    LogTrace();
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //如果当前读的包为空,而且flag为已连接
    if ((currentRead == nil) && (flags & kConnected))
    {
        //如果读的queue大于0 (里面装的是我们封装的GCDAsyncReadPacket数据包)
        if ([readQueue count] > 0)
        {
            // Dequeue the next object in the write queue
            //使得下一个对象从写的queue中离开
            
            //从readQueue中拿到第一个写的数据
            currentRead = [readQueue objectAtIndex:0];
            //移除
            [readQueue removeObjectAtIndex:0];
            
            //我们的数据包,如果是GCDAsyncSpecialPacket这种类型,这个包里装了TLS的一些设置
            //如果是这种类型的数据,那么我们就进行TLS
            if ([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]])
            {
                LogVerbose(@"Dequeued GCDAsyncSpecialPacket");
                
                // Attempt to start TLS
                //标记flag为正在读取TLS
                flags |= kStartingReadTLS;
                
                // This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set
                //只有读写都开启了TLS,才会做TLS认证
                [self maybeStartTLS];
            }
            else
            {
                LogVerbose(@"Dequeued GCDAsyncReadPacket");
                
                // Setup read timer (if needed)
                //设置读的任务超时,每次延时的时候还会调用 [self doReadData];
                [self setupReadTimerWithTimeout:currentRead->timeout];
                
                // Immediately read, if possible
                //读取数据
                [self doReadData];
            }
        }
        
        //读的队列没有数据,标记flag为,读了没有数据则断开连接状态
        else if (flags & kDisconnectAfterReads)
        {
            //如果标记有写然后断开连接
            if (flags & kDisconnectAfterWrites)
            {
                //如果写的队列为0,而且写为空
                if (([writeQueue count] == 0) && (currentWrite == nil))
                {
                    //断开连接
                    [self closeWithError:nil];
                }
            }
            else
            {
                //断开连接
                [self closeWithError:nil];
            }
        }
        //如果有安全socket。
        else if (flags & kSocketSecure)
        {
            [self flushSSLBuffers]; 
            //如果可读字节数为0
            if ([preBuffer availableBytes] == 0)
            {
                //CFStream形式TLS
                if ([self usingCFStreamForTLS]) {
                    // Callbacks never disabled
                }
                else {
                    //重新恢复读的source。因为每次开始读数据的时候,都会挂起读的source
                    [self resumeReadSource];
                }
            }
        }
    }
}

也是一系列的安全协议判断并最终走向[self doReadData];这个方法比write还长,我觉得有必要列一下这个方法里面都做了什么。。。

1.判断currentRead是否为空,为空就挂起readSource
2.判断TLS
3.从preBuffer区读取数据
4.从socket中读取数据
5.读取完代理回调
6.错误检查

- (void)doReadData
{
    LogTrace();
    
    //如果当前读取的包为空,或者flag为读取停止,这两种情况是不能去读取数据的
    if ((currentRead == nil) || (flags & kReadsPaused))
    {
        LogVerbose(@"No currentRead or kReadsPaused");
        
        // Unable to read at this time
        //如果是安全的通信,通过TLS/SSL
        if (flags & kSocketSecure)
        {
            // Here's the situation:
            // 这有一个场景
            // We have an established secure connection.
            //我们有一个确定的安全的连接
            // There may not be a currentRead, but there might be encrypted data sitting around for us.
            //可能没有立即去读,但是或许已经有加密的数据闲置在那
            // When the user does get around to issuing a read, that encrypted data will need to be decrypted.
            // 当用户开始进行一个read,这些加密的数据需要被解码
            // So why make the user wait?
            //所以为什么让用户等待?
            // We might as well get a head start on decrypting some data now.
            // 我们最好可以先进行数据解密
            // The other reason we do this has to do with detecting a socket disconnection.
            //另外的理由是,我们做这些不得不去检测socket的断开连接
            // The SSL/TLS protocol has it's own disconnection handshake.
            //SSL/TLS协议有自己的断开连接的握手
            // So when a secure socket is closed, a "goodbye" packet comes across the wire.
            //所以当一个安全连接关闭,一个“goodbye"数据包会被发送在电报中
            // We want to make sure we read the "goodbye" packet so we can properly detect the TCP disconnection.
            //我们想要确保读到“goodbye”数据包,因此我们可以确定检测到TCP连接断开
            
            //刷新SSLBuffer,把数据从链路上移到prebuffer中 (当前暂停的时候做)
            [self flushSSLBuffers];
        }
        
        //判断是否用的是 CFStream的TLS
        if ([self usingCFStreamForTLS])
        {
            // CFReadStream only fires once when there is available data.
            // It won't fire again until we've invoked CFReadStreamRead.
            //CFReadStream只会调起一次,当有可读的数据。 不会再次被调用,直到我们唤醒CFReadStreamRead。
            // source --> data --> stream
        }
        else
        {
            // If the readSource is firing, we need to pause it
            // or else it will continue to fire over and over again.
            // 
            // If the readSource is not firing,
            // we want it to continue monitoring the socket.
            //如果读的source正在触发,我们需要去停止它,否则它会持续的被触发一遍又一遍。(要等我们把现有传过来的数据读完,才能触发下一次。)
            //如果读的source没有触发。我们想要它继续去监视socket.
            //挂起source
            if (socketFDBytesAvailable > 0)
            {
                [self suspendReadSource];
            }
        }
        return;
    }
    
    //当前数据包不为空或者flag不为kReadsPaused,正式开始读取数据
    //声明是否可读,可读数据为多大
    BOOL hasBytesAvailable = NO;
    unsigned long estimatedBytesAvailable = 0;
    
    //如果用了CFStream
    if ([self usingCFStreamForTLS])
    {
        #if TARGET_OS_IPHONE
        
        // Requested CFStream, rather than SecureTransport, for TLS (via GCDAsyncSocketUseCFStreamForTLS)
        
        //不需要得到数据大小
        estimatedBytesAvailable = 0;
        //判断如果状态可读而且有可读数据,hasBytesAvailable则为YES
        if ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))
            hasBytesAvailable = YES;
        else
            hasBytesAvailable = NO;
        
        #endif
    }
    else
    {
        //拿到当前读到的数据大小,安全通道的和普通socket数据都和 socketFDBytesAvailable 有关
        estimatedBytesAvailable = socketFDBytesAvailable;
        //如果是安全socket
        if (flags & kSocketSecure)
        {
            // There are 2 buffers to be aware of here.
            // 这里有2个buffer需要知道,一个是sslPreBuffer还有一个是安全传输中未读取的buffer
            // We are using SecureTransport, a TLS/SSL security layer which sits atop TCP.
            //我们使用了安全的传输,一个TLS/SSL在TCP上
            // We issue a read to the SecureTranport API, which in turn issues a read to our SSLReadFunction.
            //我们发出read在安全传输的API上,其实就是发出read在SSLReadFunction上
            // Our SSLReadFunction then reads from the BSD socket and returns the encrypted data to SecureTransport.
            //我们SSLReadFunction 从BSD socket去读,并且返回加密的数据到安全传输中。
            // SecureTransport then decrypts the data, and finally returns the decrypted data back to us.
            // 然后安全传输返回解密的数据,最终把解密的数据返回给我们
            // The first buffer is one we create.
            //第一个buffe是我们创建的
            // SecureTransport often requests small amounts of data.
            //安全的传输经常需要少量的数据
            // This has to do with the encypted packets that are coming across the TCP stream.
            //他们不得不用加密包来穿过TCP流
            // But it's non-optimal to do a bunch of small reads from the BSD socket.
            //但是,这是不是最佳的,从BSD Socket上,进行一堆小的阅读
            // So our SSLReadFunction reads all available data from the socket (optimizing the sys call)
            //所以我们SSLReadFunction从socket中读取所有提供的数据(最佳的方式)
            // and may store excess in the sslPreBuffer.
            //可能在sslPreBuffer中存储超出的部分
            
            //预估的读取大小再加上 ssl中可读的
            estimatedBytesAvailable += [sslPreBuffer availableBytes];
            
            // The second buffer is within SecureTransport.
            //第二个Buffer在安全传输中
            // As mentioned earlier, there are encrypted packets coming across the TCP stream.
            //像之前提到的,这里有加密的包在TCP流中
            // SecureTransport needs the entire packet to decrypt it.
            //安全传输需要把整个包解密
            // But if the entire packet produces X bytes of decrypted data,
            //但是如果整个包只有 X字节是加密的数据
            // and we only asked SecureTransport for X/2 bytes of data,
            //而我们仅仅访问了 SecureTransport中一半字节的数据
            // it must store the extra X/2 bytes of decrypted data for the next read.
            // 我们必须存储另一半在下一次读取中
            // The SSLGetBufferedReadSize function will tell us the size of this internal buffer.
            //SSLGetBufferedReadSize方法,将告诉我们内部的buffer大小
            // From the documentation:
            // 
            // "This function does not block or cause any low-level read operations to occur."
            //从文档中:这个方法不会阻塞和引起低级别的读取操作发生
            
            size_t sslInternalBufSize = 0;
            //拿到SSL上下文中的大小,也就是计算我们能从SSLReead中能获取到的数据大小
            SSLGetBufferedReadSize(sslContext, &sslInternalBufSize);
            //加到预估大小中
            estimatedBytesAvailable += sslInternalBufSize;
        }
        //如果 estimatedBytesAvailable 大于0 为YES
        hasBytesAvailable = (estimatedBytesAvailable > 0);
    }
    
    //如果没有数据可读  --  一次传完的包
    if ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0))
    {
        LogVerbose(@"No data available to read...");
        
        //而且不是用CFStream
        if (![self usingCFStreamForTLS])
        {
            // Need to wait for readSource to fire and notify us of
            // available data in the socket's internal read buffer.
            //恢复读的source
            [self resumeReadSource];
        }
        return;
    }
    //如果开始 kStartingReadTLS,说明正在准备握手,那么我们不能进行读取操作,要直接返回
    if (flags & kStartingReadTLS)
    {
        LogVerbose(@"Waiting for SSL/TLS handshake to complete");
        
        // The readQueue is waiting for SSL/TLS handshake to complete.
        //如果正在写的TLS,如果上一次是阻塞错误,那么在重新去握手,(防止一次握手阻塞而失败导致不再握手)
        if (flags & kStartingWriteTLS)
        {
            //如果用的是非CFStreamTLS,即安全的TLS  而且上一次握手错误为 IO阻塞的
            if ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)
            {
                // We are in the process of a SSL Handshake.
                // We were waiting for incoming data which has just arrived.
                //SSL的握手
                [self ssl_continueSSLHandshake];
            }
        }
        else
        {
            // We are still waiting for the writeQueue to drain and start the SSL/TLS process.
            // We now know data is available to read.
            
            //如果当前不是CFStream的方式
            if (![self usingCFStreamForTLS])
            {
                // Suspend the read source or else it will continue to fire nonstop.
                //挂起读的queue
                [self suspendReadSource];
            }
        }
        
        return;
    }
    
    //是否完成读的操作
    BOOL done        = NO;  // Completed read operation
    //错误
    NSError *error   = nil; // Error occurred
    
    //当前总读的数据量
    NSUInteger totalBytesReadForCurrentRead = 0;
    
    // 
    // STEP 1 - READ FROM PREBUFFER
    // 
    //先从提前缓冲区去读,如果缓冲区可读大小大于0
    if ([preBuffer availableBytes] > 0)
    {
        // There are 3 types of read packets:
        //
        // 1) Read all available data.
        // 2) Read a specific length of data.
        // 3) Read up to a particular terminator.
        //3种类型的读法,1、全读、2、读取特定长度、3、读取到一个明确的界限
        
        NSUInteger bytesToCopy;
        
        //如果当前读的数据界限不为空
        if (currentRead->term != nil)
        {
            // Read type #3 - read up to a terminator
            //直接读到界限
            bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
        }
        else
        {
            // Read type #1 or #2
            //读取数据,读到指定长度或者数据包的长度为止
            bytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]];
        }
        
        // Make sure we have enough room in the buffer for our read.
        //从上两步拿到我们需要读的长度,去看看有没有空间去存储
        [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
        
        // Copy bytes from prebuffer into packet buffer

        //拿到我们需要追加数据的指针位置
        //当前读的数据 + 开始偏移 + 已经读完的??
        uint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset +
                                                                          currentRead->bytesDone;
        //从prebuffer处复制过来数据,bytesToCopy长度
        memcpy(buffer, [preBuffer readBuffer], bytesToCopy);
        
        // Remove the copied bytes from the preBuffer
        //从preBuffer移除掉已经复制的数据
        [preBuffer didRead:bytesToCopy];
        
        
        LogVerbose(@"copied(%lu) preBufferLength(%zu)", (unsigned long)bytesToCopy, [preBuffer availableBytes]);
        
        // Update totals
        
        //已读的数据加上
        currentRead->bytesDone += bytesToCopy;
        //当前已读的数据加上
        totalBytesReadForCurrentRead += bytesToCopy;
        
        // Check to see if the read operation is done
        //判断是不是读完了
        if (currentRead->readLength > 0)
        {
            // Read type #2 - read a specific length of data
            //如果已读 == 需要读的长度,说明已经读完
            done = (currentRead->bytesDone == currentRead->readLength);
        }
        //判断界限标记
        else if (currentRead->term != nil)
        {
            // Read type #3 - read up to a terminator
            
            // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method
            //如果没做完,且读的最大长度大于0,去判断是否溢出
            if (!done && currentRead->maxLength > 0)
            {
                // We're not done and there's a set maxLength.
                // Have we reached that maxLength yet?
                
                //如果已读的大小大于最大的大小,则报溢出错误
                if (currentRead->bytesDone >= currentRead->maxLength)
                {
                    error = [self readMaxedOutError];
                }
            }
        }
        else
        {
            // Read type #1 - read all available data
            // 
            // We're done as soon as
            // - we've read all available data (in prebuffer and socket)
            // - we've read the maxLength of read packet.
            //判断已读大小和最大大小是否相同,相同则读完
            done = ((currentRead->maxLength > 0) && (currentRead->bytesDone == currentRead->maxLength));
        }
        
    }
    
    // 
    // STEP 2 - READ FROM SOCKET
    // 从socket中去读取
    
    //是否读到EOFException ,这个错误指的是文件结尾了还在继续读,就会导致这个错误被抛出
    BOOL socketEOF = (flags & kSocketHasReadEOF) ? YES : NO;  // Nothing more to read via socket (end of file)
    
    //如果没完成,且没错,没读到结尾,且没有可读数据了
    BOOL waiting   = !done && !error && !socketEOF && !hasBytesAvailable; // Ran out of data, waiting for more
    
    //如果没完成,且没错,没读到结尾,有可读数据
    if (!done && !error && !socketEOF && hasBytesAvailable)
    {
        //断言,有可读数据
        NSAssert(([preBuffer availableBytes] == 0), @"Invalid logic");
        //是否读到preBuffer中去
        BOOL readIntoPreBuffer = NO;
        uint8_t *buffer = NULL;
        size_t bytesRead = 0;
        
        //如果flag标记为安全socket
        if (flags & kSocketSecure)
        {
            //如果使用CFStream
            if ([self usingCFStreamForTLS])
            {
                #if TARGET_OS_IPHONE
                
                // Using CFStream, rather than SecureTransport, for TLS
                //默认读的大小32KB
                NSUInteger defaultReadLength = (1024 * 32);
                
                //决定我们读的字节大小,和是否使用prebuffer
                NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
                                                                   shouldPreBuffer:&readIntoPreBuffer];
                
                // Make sure we have enough room in the buffer for our read.
                //
                // We are either reading directly into the currentRead->buffer,
                // or we're reading into the temporary preBuffer.
                //如果使用preBuffer,则去确保有这么大的空间来存
                if (readIntoPreBuffer)
                {
                    [preBuffer ensureCapacityForWrite:bytesToRead];
                    //拿到写的buffer
                    buffer = [preBuffer writeBuffer];
                }
                //不用prebuffer
                else
                {
                    //确保大小,其实不用。。
                    [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
                    
                    //获取到当前buffer上次写到的偏移位置
                    buffer = (uint8_t *)[currentRead->buffer mutableBytes]
                           + currentRead->startOffset
                           + currentRead->bytesDone;
                }
                
                // Read data into buffer
                
#pragma mark - 开始读取数据 CFStream
                //从readStream中读取数据,到buffer中
                CFIndex result = CFReadStreamRead(readStream, buffer, (CFIndex)bytesToRead);
                LogVerbose(@"CFReadStreamRead(): result = %i", (int)result);
                
                //读取失败
                if (result < 0)
                {
                    error = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream);
                }
                // 读取抛出了EOFException,到数据边界了
                else if (result == 0)
                {
                    socketEOF = YES;
                }
                //正常读取
                else
                {
                    waiting = YES;
                    bytesRead = (size_t)result;
                }
                
                // We only know how many decrypted bytes were read.
                // The actual number of bytes read was likely more due to the overhead of the encryption.
                // So we reset our flag, and rely on the next callback to alert us of more data.
                
                //移除仍然有数据可读的标记
                flags &= ~kSecureSocketHasBytesAvailable;
                
                #endif
            }
            else
            {
                //用安全传输来
                // Using SecureTransport for TLS
                //
                // We know:
                // - how many bytes are available on the socket
                // - how many encrypted bytes are sitting in the sslPreBuffer
                // - how many decypted bytes are sitting in the sslContext
                //
                // But we do NOT know:
                // - how many encypted bytes are sitting in the sslContext
                //
                // So we play the regular game of using an upper bound instead.
                
                //也是默认32KB
                NSUInteger defaultReadLength = (1024 * 32);
                
                //如果默认大小小于预估的大小,则让默认大小的 =  预估大小 + 16KB ,16KB干嘛用的??
                if (defaultReadLength < estimatedBytesAvailable) {
                    defaultReadLength = estimatedBytesAvailable + (1024 * 16);
                }
                //去要读的大小,还有是否走Prebuffer
                NSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength
                                                                   shouldPreBuffer:&readIntoPreBuffer];
                
                //如果要读的大小大于最大值 ,则让其等于最大值
                if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t
                    bytesToRead = SIZE_MAX;
                }
                
                // Make sure we have enough room in the buffer for our read.
                //
                // We are either reading directly into the currentRead->buffer,
                // or we're reading into the temporary preBuffer.
                
                //还是去确保最大空间,并且拿到写的头指针
                if (readIntoPreBuffer)
                {
                    [preBuffer ensureCapacityForWrite:bytesToRead];
                    
                    buffer = [preBuffer writeBuffer];
                }
                else
                {
                    [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
                    
                    buffer = (uint8_t *)[currentRead->buffer mutableBytes]
                           + currentRead->startOffset
                           + currentRead->bytesDone;
                }
                
                // The documentation from Apple states:
                // 
                //     "a read operation might return errSSLWouldBlock,
                //      indicating that less data than requested was actually transferred"
                // 
                // However, starting around 10.7, the function will sometimes return noErr,
                // even if it didn't read as much data as requested. So we need to watch out for that.
                
                OSStatus result;
            
#pragma mark - 开始读取数据 SSLRead
                //循环去读
                do
                {
                    //拿到当前写到的buffer位置
                    //头指针 + 读了的大小
                    void *loop_buffer = buffer + bytesRead;
                    
                    //得到还需要读的大小
                    size_t loop_bytesToRead = (size_t)bytesToRead - bytesRead;
                    //设置这一次循环读的进度
                    size_t loop_bytesRead = 0;
                    
                    //用ssl方式去读取数据,头指针为loop_buffer,大小为loop_bytesToRead,进度为loop_bytesRead
                    result = SSLRead(sslContext, loop_buffer, loop_bytesToRead, &loop_bytesRead);
                    LogVerbose(@"read from secure socket = %u", (unsigned)loop_bytesRead);
                    
                    //读了的大小加进度
                    bytesRead += loop_bytesRead;
                    
                }
                //如果没出错,且读的大小小于需要读的大小,就一直循环
                while ((result == noErr) && (bytesRead < bytesToRead));
                
                //如果出错
                if (result != noErr)
                {
                    //如果是IO阻塞的错误, waiting
                    if (result == errSSLWouldBlock)
                        waiting = YES;
                    else
                    {
                        //如果是SSL连接断开的错误
                        if (result == errSSLClosedGraceful || result == errSSLClosedAbort)
                        {
                            // We've reached the end of the stream.
                            // Handle this the same way we would an EOF from the socket.
                            //说明到边界了
                            socketEOF = YES;
                            //把错误赋值给SSLErrCode
                            sslErrCode = result;
                        }
                        else
                        {
                            //直接拿到SSL数据错误
                            error = [self sslError:result];
                        }
                    }
                    // It's possible that bytesRead > 0, even if the result was errSSLWouldBlock.
                    //很有可能bytesRead中有数据,即使结果是IO阻塞的错误
                    // This happens when the SSLRead function is able to read some data,
                    // but not the entire amount we requested.
                    
                    
                    if (bytesRead <= 0)
                    {
                        bytesRead = 0;
                    }
                }
                //不要修改 socketFDBytesAvailable 可读数据大小,因为这个会在 SSLReadFunction中被修改
                // Do not modify socketFDBytesAvailable.
                // It will be updated via the SSLReadFunction().
            }
        }
        else
        {
            // Normal socket operation
            //普通的socket 操作
            
            NSUInteger bytesToRead;
            
            // There are 3 types of read packets:
            //
            // 1) Read all available data.
            // 2) Read a specific length of data.
            // 3) Read up to a particular terminator.
            
            //和上面类似,读取到边界标记??不是吧
            if (currentRead->term != nil)
            {
                // Read type #3 - read up to a terminator
                
                //读这个长度,如果到maxlength,就用maxlength。看如果可用空间大于需要读的空间,则不用prebuffer
                bytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable
                                                     shouldPreBuffer:&readIntoPreBuffer];
            }
            
            else
            {
                // Read type #1 or #2
                //直接读这个长度,如果到maxlength,就用maxlength
                bytesToRead = [currentRead readLengthForNonTermWithHint:estimatedBytesAvailable];
            }
            
            //大于最大值,则先读最大值
            if (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t (read param 3)
                bytesToRead = SIZE_MAX;
            }
            
            // Make sure we have enough room in the buffer for our read.
            //
            // We are either reading directly into the currentRead->buffer,
            // or we're reading into the temporary preBuffer.
            
            if (readIntoPreBuffer)
            {
                [preBuffer ensureCapacityForWrite:bytesToRead];
                
                buffer = [preBuffer writeBuffer];
            }
            else
            {
                [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];
                
                buffer = (uint8_t *)[currentRead->buffer mutableBytes]
                       + currentRead->startOffset
                       + currentRead->bytesDone;
            }
            
            // Read data into buffer
            
            int socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;
#pragma mark - 开始读取数据,最普通的形式 read
            
            //读数据
            ssize_t result = read(socketFD, buffer, (size_t)bytesToRead);
            LogVerbose(@"read from socket = %i", (int)result);
            //读取错误
            if (result < 0)
            {
                //EWOULDBLOCK IO阻塞
                if (errno == EWOULDBLOCK)
                    //先等待
                    waiting = YES;
                else
                    //得到错误
                    error = [self errnoErrorWithReason:@"Error in read() function"];
                //把可读取的长度设置为0
                socketFDBytesAvailable = 0;
            }
            //读到边界了
            else if (result == 0)
            {
                socketEOF = YES;
                socketFDBytesAvailable = 0;
            }
            //正常
            else
            {
                //设置读到的数据长度
                bytesRead = result;
                
                //如果读到的数据小于应该读的长度,说明这个包没读完
                if (bytesRead < bytesToRead)
                {
                    // The read returned less data than requested.
                    // This means socketFDBytesAvailable was a bit off due to timing,
                    // because we read from the socket right when the readSource event was firing.
                    socketFDBytesAvailable = 0;
                }
                //正常
                else
                {
                    //如果 socketFDBytesAvailable比读了的数据小的话,直接置为0
                    if (socketFDBytesAvailable <= bytesRead)
                        socketFDBytesAvailable = 0;
                    //减去已读大小
                    else
                        socketFDBytesAvailable -= bytesRead;
                }
                //如果 socketFDBytesAvailable 可读数量为0,把读的状态切换为等待
                if (socketFDBytesAvailable == 0)
                {
                    waiting = YES;
                }
            }
        }
        
        //如果这次读的字节大于0
        if (bytesRead > 0)
        {
            // Check to see if the read operation is done
            //检查这个包的数据是否读完,用readLength来读的
            if (currentRead->readLength > 0)
            {
                // Read type #2 - read a specific length of data
                // 
                // Note: We should never be using a prebuffer when we're reading a specific length of data.
                //我们读取固定大小的时候是永远不用写到prebuffer中去的
                
                //断言,是不需要写到prebuffer中去的
                NSAssert(readIntoPreBuffer == NO, @"Invalid logic");
                
                //加上读的数量
                currentRead->bytesDone += bytesRead;
                //把这一次读的数量加上来
                totalBytesReadForCurrentRead += bytesRead;
                //判断是否已读完
                done = (currentRead->bytesDone == currentRead->readLength);
            }
            
            //用边界来读的
            else if (currentRead->term != nil)
            {
                // Read type #3 - read up to a terminator
                //如果是往buffer中读的
                if (readIntoPreBuffer)
                {
                    // We just read a big chunk of data into the preBuffer
                    
                    //移动writeBuffer的指针
                    [preBuffer didWrite:bytesRead];
                    LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]);
                    
                    // Search for the terminating sequence
                    
                    //拿到需要读取的大小,根据term,并且判断是否已读完
                    NSUInteger bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];
                    LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToCopy);
                    
                    // Ensure there's room on the read packet's buffer
                    //确保有这么大的空间
                    [currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];
                    
                    // Copy bytes from prebuffer into read buffer
                    
                    uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
                                                                                     + currentRead->bytesDone;
                    
#pragma mark - 把数据从preBuffer中移到currentRead上
                    memcpy(readBuf, [preBuffer readBuffer], bytesToCopy);
                    
                    // Remove the copied bytes from the prebuffer
                    //标记已经读了这么多数据
                    [preBuffer didRead:bytesToCopy];
                    LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
                    
                    // Update totals
                    currentRead->bytesDone += bytesToCopy;
                    totalBytesReadForCurrentRead += bytesToCopy;
                    
                    // Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method above
                }
                
                //没有用prebuffer
                else
                {
                    // We just read a big chunk of data directly into the packet's buffer.
                    // We need to move any overflow into the prebuffer.
                    //我们需要把数据流向prebuffer?
                    
                    //拿到粘包长度,(为溢出长度,溢出的我们要写到prebuffer中去。给下一个包去读)
                    NSInteger overflow = [currentRead searchForTermAfterPreBuffering:bytesRead];
                    
                    //如果为0,说明完全匹配
                    if (overflow == 0)
                    {
                        //加上这次读取的字节数
                        currentRead->bytesDone += bytesRead;
                        //总的读取字节数
                        totalBytesReadForCurrentRead += bytesRead;
                        //标志读取完成
                        done = YES;
                    }
                    
                    //说明读取的数据总长度比当前包大(粘包)
                    else if (overflow > 0)
                    {
                        
                        //当前包内的长度
                        NSInteger underflow = bytesRead - overflow;
                        
                        // Copy excess data into preBuffer
                        
                        LogVerbose(@"copying %ld overflow bytes into preBuffer", (long)overflow);
                        //确保preBuffer有这么大的大小
                        [preBuffer ensureCapacityForWrite:overflow];
                        
                        //把buffer往后移,去掉重合的数据大小
                        uint8_t *overflowBuffer = buffer + underflow;
                        
                        //写到writeBuffer中,长度为 overflow(非重合部分)
                        memcpy([preBuffer writeBuffer], overflowBuffer, overflow);
                        //后移写指针
                        [preBuffer didWrite:overflow];
                        LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]);
                        
                        // Note: The completeCurrentRead method will trim the buffer for us.
                        
                        //加上已读的大小(非粘包的)
                        currentRead->bytesDone += underflow;
                        //这次总共读取的大小
                        totalBytesReadForCurrentRead += underflow;
                        //当前读取完成
                        done = YES;
                    }
                    //数据还没达到边界
                    else
                    {
                        // The term was not found within the data that we read.
                        //已读的加上 bytesRead
                        currentRead->bytesDone += bytesRead;
                        totalBytesReadForCurrentRead += bytesRead;
                        //标记为未完成
                        done = NO;
                    }
                }
                
                //如果未完成 而且当前包的数据包最大长度大于0
                if (!done && currentRead->maxLength > 0)
                {
                    // We're not done and there's a set maxLength.
                    // Have we reached that maxLength yet?
                    //判断写的大小 是否达到包的最大值
                    if (currentRead->bytesDone >= currentRead->maxLength)
                    {
                        //得到读取溢出的错误
                        error = [self readMaxedOutError];
                    }
                }
            }
            
            //没边界,没给定长度(无法判断当前包结尾)
            else
            {
                // Read type #1 - read all available data
                //如果从prebuffer中读取
                if (readIntoPreBuffer)
                {
                    // We just read a chunk of data into the preBuffer
                    
                    //指针后移
                    [preBuffer didWrite:bytesRead];
                    
                    // Now copy the data into the read packet.
                    // 
                    // Recall that we didn't read directly into the packet's buffer to avoid
                    // over-allocating memory since we had no clue how much data was available to be read.
                    // 
                    // Ensure there's room on the read packet's buffer
                    
                    //确保currentRead中有bytesRead大小可用
                    [currentRead ensureCapacityForAdditionalDataOfLength:bytesRead];
                    
                    // Copy bytes from prebuffer into read buffer
                    
                    uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset
                                                                                     + currentRead->bytesDone;
                    
                    //拿到指针赋值
                    memcpy(readBuf, [preBuffer readBuffer], bytesRead);
                    
                    // Remove the copied bytes from the prebuffer
                    //标记读了这么多数据
                    [preBuffer didRead:bytesRead];
                    
                    // Update totals
                    //更新已读
                    currentRead->bytesDone += bytesRead;
                    totalBytesReadForCurrentRead += bytesRead;
                }
                //在currentRead中的话直接加就行
                else
                {
                    currentRead->bytesDone += bytesRead;
                    totalBytesReadForCurrentRead += bytesRead;
                }
                //因为无法判断结尾,所以每次读都会直接标记为YES,即一个包完成
                done = YES;
            }
            
        } // if (bytesRead > 0)
        
    } // if (!done && !error && !socketEOF && hasBytesAvailable)
    
    
    //如果未完成,而且没有应读长度和边界符
    if (!done && currentRead->readLength == 0 && currentRead->term == nil)
    {
        // Read type #1 - read all available data
        // 
        // We might arrive here if we read data from the prebuffer but not from the socket.
        //只要当前总共读的数量大于0,就认为完成了,因为无从判断
        done = (totalBytesReadForCurrentRead > 0);
    }
    
    // Check to see if we're done, or if we've made progress
    //检查是否读完
    if (done)
    {
        //完成这次数据的读取
        [self completeCurrentRead];
        //如果没出错,没有到边界,prebuffer中还有可读数据
        if (!error && (!socketEOF || [preBuffer availableBytes] > 0))
        {
            //让读操作离队,继续进行下一次读取
            [self maybeDequeueRead];
        }
    }
    
    //如果这次读的数量大于0
    else if (totalBytesReadForCurrentRead > 0)
    {
        // We're not done read type #2 or #3 yet, but we have read in some bytes

        __strong id theDelegate = delegate;
        
        //如果响应读数据进度的代理
        if (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)])
        {
            long theReadTag = currentRead->tag;
            
            //代理queue中回调出去
            dispatch_async(delegateQueue, ^{ @autoreleasepool {
                
                [theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag];
            }});
        }
    }
    
    // Check for errors
    //检查错误
    if (error)
    {
        //如果有错直接报错断开连接
        [self closeWithError:error];
    }
    //如果是读到边界错误
    else if (socketEOF)
    {
        [self doReadEOF];
    }
    
    //如果是等待
    else if (waiting)
    {
        //如果用的是CFStream,则读取数据和source无关
        //非CFStream形式
        if (![self usingCFStreamForTLS])
        {
            // Monitor the socket for readability (if we're not already doing so)
            //重新恢复source
            [self resumeReadSource];
        }
    }
    // Do not add any code here without first adding return statements in the error cases above.
}

特别特别长...接下来就是关闭socket了

5.CLOSE
- (void)closeWithError:(NSError *)error
{
    LogTrace();
    //先判断当前queue是不是IsOnSocketQueueOrTargetQueueKey
    NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
    
    //关闭连接超时
    [self endConnectTimeout];
    
    if (currentRead != nil)  [self endCurrentRead];
    if (currentWrite != nil) [self endCurrentWrite];
    
    [readQueue removeAllObjects];
    [writeQueue removeAllObjects];
    
    [preBuffer reset];
    
    #if TARGET_OS_IPHONE
    {
        if (readStream || writeStream)
        {
            [self removeStreamsFromRunLoop];
            
            if (readStream)
            {
                CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
                CFReadStreamClose(readStream);
                CFRelease(readStream);
                readStream = NULL;
            }
            if (writeStream)
            {
                CFWriteStreamSetClient(writeStream, kCFStreamEventNone, NULL, NULL);
                CFWriteStreamClose(writeStream);
                CFRelease(writeStream);
                writeStream = NULL;
            }
        }
    }
    #endif
    
    [sslPreBuffer reset];
    sslErrCode = lastSSLHandshakeError = noErr;
    
    if (sslContext)
    {
        // Getting a linker error here about the SSLx() functions?
        // You need to add the Security Framework to your application.
        //关闭sslContext
        SSLClose(sslContext);
        
        #if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)
        CFRelease(sslContext);
        #else
        SSLDisposeContext(sslContext);
        #endif
        
        sslContext = NULL;
    }
    
    // For some crazy reason (in my opinion), cancelling a dispatch source doesn't
    // invoke the cancel handler if the dispatch source is paused.
    // So we have to unpause the source if needed.
    // This allows the cancel handler to be run, which in turn releases the source and closes the socket.
    
    //如果这些source都为空,直接只关闭socket就可以
    if (!accept4Source && !accept6Source && !acceptUNSource && !readSource && !writeSource)
    {
        LogVerbose(@"manually closing close");

        if (socket4FD != SOCKET_NULL)
        {
            LogVerbose(@"close(socket4FD)");
            close(socket4FD);
            socket4FD = SOCKET_NULL;
        }

        if (socket6FD != SOCKET_NULL)
        {
            LogVerbose(@"close(socket6FD)");
            close(socket6FD);
            socket6FD = SOCKET_NULL;
        }
        
        if (socketUN != SOCKET_NULL)
        {
            LogVerbose(@"close(socketUN)");
            close(socketUN);
            socketUN = SOCKET_NULL;
            //断开Unix domin socket
            unlink(socketUrl.path.fileSystemRepresentation);
            socketUrl = nil;
        }
    }
    else
    {
        //都去取消souce先
        if (accept4Source)
        {
            LogVerbose(@"dispatch_source_cancel(accept4Source)");
            dispatch_source_cancel(accept4Source);
            
            // We never suspend accept4Source
            
            accept4Source = NULL;
        }
        
        if (accept6Source)
        {
            LogVerbose(@"dispatch_source_cancel(accept6Source)");
            dispatch_source_cancel(accept6Source);
            
            // We never suspend accept6Source
            
            accept6Source = NULL;
        }
        
        if (acceptUNSource)
        {
            LogVerbose(@"dispatch_source_cancel(acceptUNSource)");
            dispatch_source_cancel(acceptUNSource);
            
            // We never suspend acceptUNSource
            
            acceptUNSource = NULL;
        }
    
        //读写source需要resume,否则如果是suspend状态的话,cancel不会被调用
        if (readSource)
        {
            LogVerbose(@"dispatch_source_cancel(readSource)");
            dispatch_source_cancel(readSource);
            
            [self resumeReadSource];
            
            readSource = NULL;
        }
        
        if (writeSource)
        {
            LogVerbose(@"dispatch_source_cancel(writeSource)");
            dispatch_source_cancel(writeSource);
            
            [self resumeWriteSource];
            
            writeSource = NULL;
        }
        
        // The sockets will be closed by the cancel handlers of the corresponding source
        socket4FD = SOCKET_NULL;
        socket6FD = SOCKET_NULL;
        socketUN = SOCKET_NULL;
    }
    
    // If the client has passed the connect/accept method, then the connection has at least begun.
    // Notify delegate that it is now ending.
    //判断是否sokcet开启
    BOOL shouldCallDelegate = (flags & kSocketStarted) ? YES : NO;
    BOOL isDeallocating = (flags & kDealloc) ? YES : NO;
    
    // Clear stored socket info and all flags (config remains as is)
    //清楚socket的相关信息,和所有标记
    socketFDBytesAvailable = 0;
    flags = 0;
    sslWriteCachedLength = 0;
    
    if (shouldCallDelegate)
    {
        __strong id theDelegate = delegate;
        //判断是否需要传自己过去,如果已经被销毁,就传nil
        __strong id theSelf = isDeallocating ? nil : self;
        
        //调用断开连接的代理
        if (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)])
        {
            dispatch_async(delegateQueue, ^{ @autoreleasepool {
                
                [theDelegate socketDidDisconnect:theSelf withError:error];
            }});
        }   
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容