第2月第1天 GCDAsyncSocket dispatch_source_set_event_handler
Posted lianhuaren
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第2月第1天 GCDAsyncSocket dispatch_source_set_event_handler相关的知识,希望对你有一定的参考价值。
一、GCDAsyncSocket的核心就是dispatch_source_set_event_handler
1.accpet回调
accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue); int socketFD = socket4FD; dispatch_source_t acceptSource = accept4Source; dispatch_source_set_event_handler(accept4Source, ^{ @autoreleasepool { LogVerbose(@"event4Block"); unsigned long i = 0; unsigned long numPendingConnections = dispatch_source_get_data(acceptSource); LogVerbose(@"numPendingConnections: %lu", numPendingConnections); while ([self doAccept:socketFD] && (++i < numPendingConnections)); }});
2.read,write回调
readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue); writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue); // Setup event handlers dispatch_source_set_event_handler(readSource, ^{ @autoreleasepool { LogVerbose(@"readEventBlock"); socketFDBytesAvailable = dispatch_source_get_data(readSource); LogVerbose(@"socketFDBytesAvailable: %lu", socketFDBytesAvailable); if (socketFDBytesAvailable > 0) [self doReadData]; else [self doReadEOF]; }}); dispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool { LogVerbose(@"writeEventBlock"); flags |= kSocketCanAcceptBytes; [self doWriteData]; }});
二,缓存区
1.创建
GCDAsyncReadPacket没有传入buffer,则readpacket没有缓冲区,socket可读时会放入preBuffer
- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag { [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag]; } - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset tag:(long)tag { [self readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag]; } - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag { [self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:length tag:tag]; } - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger)offset maxLength:(NSUInteger)maxLength tag:(long)tag { if ([data length] == 0) { LogWarn(@"Cannot read: [data length] == 0"); return; } if (offset > [buffer length]) { LogWarn(@"Cannot read: offset > [buffer length]"); return; } if (maxLength > 0 && maxLength < [data length]) { LogWarn(@"Cannot read: maxLength > 0 && maxLength < [data length]"); return; } GCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer startOffset:offset maxLength:maxLength timeout:timeout readLength:0 terminator:data tag:tag]; dispatch_async(socketQueue, ^{ @autoreleasepool { LogTrace(); if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites)) { [readQueue addObject:packet]; [self maybeDequeueRead]; } }}); // Do not rely on the block being run in order to release the packet, // as the queue might get released without the block completing. }
三、面向对象封装
1.socket可读的时候先用preBuffer接收,拷贝到currentRead->buffer中,为生产者-消费者模式.
GCDAsyncReadPacket *currentRead; GCDAsyncWritePacket *currentWrite; GCDAsyncSocketPreBuffer *preBuffer;
uint8_t *buffer; if (readIntoPreBuffer) { [preBuffer ensureCapacityForWrite:bytesToRead]; buffer = [preBuffer writeBuffer]; } 。。。 int socketFD = (socket4FD == SOCKET_NULL) ? socket6FD : socket4FD; ssize_t result = read(socketFD, buffer, (size_t)bytesToRead); LogVerbose(@"read from socket = %i", (int)result); 。。。 if (readIntoPreBuffer) { // We just read a big chunk of data into the preBuffer [preBuffer didWrite:bytesRead]; LogVerbose(@"read data into preBuffer - preBuffer.length = %zu", [preBuffer availableBytes]); // Search for the terminating sequence bytesToRead = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done]; LogVerbose(@"copying %lu bytes from preBuffer", (unsigned long)bytesToRead); // Ensure there‘s room on the read packet‘s buffer [currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead]; // Copy bytes from prebuffer into read buffer uint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset + currentRead->bytesDone; memcpy(readBuf, [preBuffer readBuffer], bytesToRead); // Remove the copied bytes from the prebuffer [preBuffer didRead:bytesToRead]; LogVerbose(@"preBuffer.length = %zu", [preBuffer availableBytes]); // Update totals currentRead->bytesDone += bytesToRead; totalBytesReadForCurrentRead += bytesToRead; // Our ‘done‘ variable was updated via the readLengthForTermWithPreBuffer:found: method above }
以上是关于第2月第1天 GCDAsyncSocket dispatch_source_set_event_handler的主要内容,如果未能解决你的问题,请参考以下文章