美文网首页
GCDAsyncSocket GCD 的使用(1)

GCDAsyncSocket GCD 的使用(1)

作者: 老猫_2017 | 来源:发表于2020-01-21 10:40 被阅读0次
// dispatch_queue_set_specific 设置 key - value, 队列判断使用
IsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;
        
        void *nonNullUnusedPointer = (__bridge void *)self;
        dispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);

// 判断队列,保证在特定的队列,执行任务
- (void)dealloc
{
    ...
    
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
    {
        [self closeWithError:nil];
    }
    else
    {
        dispatch_sync(socketQueue, ^{
            [self closeWithError:nil];
        });
    }
    
    ...
}


// 保证同步执行
+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError* __autoreleasing *)error
{
  __block BOOL errorOccured = NO;
  
  GCDAsyncSocket *socket = [[[self class] alloc] initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq];
  dispatch_sync(socket->socketQueue, ^{ @autoreleasepool {
    ...
  }});
  
  return errorOccured? nil: socket;
}

// 保证唯一队列, 获取信息,多线程保护
- (id)delegate
{
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))
    {
        return delegate;
    }
    else
    {
        __block id result;
        dispatch_sync(socketQueue, ^{
            result = self->delegate;
        });
        return result;
    }
}

// 多线程保护, 将执行的任务, 封装成block 块儿,提交到特定的队列上,异步,或 同步执行.
- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously
{
    dispatch_block_t block = ^{
        self->delegate = newDelegate;
    };
    
    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {
        block();
    }
    else {
        if (synchronously)
            dispatch_sync(socketQueue, block);
        else
            dispatch_async(socketQueue, block);
    }
}

// return_from_block 还是有意义的
dispatch_block_t block = ^{ @autoreleasepool {
     ...
            // 可以定义宏,明确return 的含义
            return_from_block;
        }
};

dispatch_queue_set_specific, dispatch_get_specific 用来判断队列

将任务封装block,在异步,或者 同步时,执行 block

宏定义 return_from_block 来明确 return 所在的含义
block 内部,weak strong == nil 直接return

// dispatch_source_type read 读文件描述符
self->accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, self->socket4FD, 0, self->socketQueue);

// event handler
dispatch_source_set_event_handler(self->accept4Source, ^{ @autoreleasepool {
            #pragma clang diagnostic push
            #pragma clang diagnostic warning "-Wimplicit-retain-self"
                // 很赞的,一个写法
                __strong GCDAsyncSocket *strongSelf = weakSelf;
                if (strongSelf == nil) return_from_block;
                
                LogVerbose(@"event4Block");
                
                unsigned long i = 0;
    // get data 是获取可用字节的长度
                unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
                
                LogVerbose(@"numPendingConnections: %lu", numPendingConnections);
                // 执行读取 socket 字节数
                while ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));
                
            #pragma clang diagnostic pop
            }});

// cancel_hander
dispatch_source_set_cancel_handler(self->accept4Source, ^{
            #pragma clang diagnostic push
            #pragma clang diagnostic warning "-Wimplicit-retain-self"
                
                #if !OS_OBJECT_USE_OBJC
                LogVerbose(@"dispatch_release(accept4Source)");
                dispatch_release(acceptSource);
                #endif
                
                LogVerbose(@"close(socket4FD)");
                close(socketFD);
            
            #pragma clang diagnostic pop
            });

// 开始准备读数据
            dispatch_resume(self->accept4Source);
// cancel source
            dispatch_source_cancel(accept4Source);

// dispatch_after 延时执行任务
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), socketQueue, ^{
            [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex];
        });


// source timer
        connectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);
    // timer handler
        dispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool {
        #pragma clang diagnostic push
        #pragma clang diagnostic warning "-Wimplicit-retain-self"
        
            __strong GCDAsyncSocket *strongSelf = weakSelf;
            if (strongSelf == nil) return_from_block;
            
            [strongSelf doConnectTimeout];
            
        #pragma clang diagnostic pop
        }});

dispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));
        dispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0);
        
        dispatch_resume(connectTimer);
// cancel timer
if (connectTimer)
    {
        dispatch_source_cancel(connectTimer);
        connectTimer = NULL;
    }

// read source
    readSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue);
// 挂起暂停
        dispatch_suspend(readSource);
// 继续执行任务
        dispatch_resume(readSource);


// write source
    writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue);


dispatch_source DISPATCH_SOURCE_TYPE_READ ,一般读文件,读流等

cancel_hander 关闭时,关闭正在打开的文件.

event_handler 用来接收事件,

dispatch_source_get_data 获取,获取到的字节数.

dispatch_after 延迟执行任务

在设置 read 的 event hander时, 读文件内容,或者 ,读socket 流的内容

相关文章

网友评论

      本文标题:GCDAsyncSocket GCD 的使用(1)

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