1. 程式人生 > IOS開發 >iOS GCDAsyncSocket原始碼分析(二)

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,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,(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,(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,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,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,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];
			}});
		}	
	}
}
複製程式碼