+ (void)startCFStreamThreadIfNeeded
{
LogTrace(); static dispatch_once_t predicate;
dispatch_once(&predicate, ^{ cfstreamThreadRetainCount = 0;
cfstreamThreadSetupQueue = dispatch_queue_create("GCDAsyncSocket-CFStreamThreadSetup", DISPATCH_QUEUE_SERIAL);
}); dispatch_sync(cfstreamThreadSetupQueue, ^{ @autoreleasepool { if (++cfstreamThreadRetainCount == 1)
{
cfstreamThread = [[NSThread alloc] initWithTarget:self
selector:@selector(cfstreamThread)
object:nil];
[cfstreamThread start];
}
}});
} + (void)cfstreamThread { @autoreleasepool
{
[[NSThread currentThread] setName:GCDAsyncSocketThreadName]; LogInfo(@"CFStreamThread: Started"); // We can't run the run loop unless it has an associated input source or a timer.
// So we'll just create a timer that will never fire - unless the server runs for decades.
[NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
target:self
selector:@selector(ignore:)
userInfo:nil
repeats:YES]; NSThread *currentThread = [NSThread currentThread];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop]; BOOL isCancelled = [currentThread isCancelled]; while (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])
{
isCancelled = [currentThread isCancelled];
} LogInfo(@"CFStreamThread: Stopped");
}} - (BOOL)addStreamsToRunLoop
{
LogTrace(); NSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @"Must be dispatched on socketQueue");
NSAssert((readStream != NULL && writeStream != NULL), @"Read/Write stream is null"); if (!(flags & kAddedStreamsToRunLoop))
{
LogVerbose(@"Adding streams to runloop..."); [[self class] startCFStreamThreadIfNeeded];
[[self class] performSelector:@selector(scheduleCFStreams:)
onThread:cfstreamThread
withObject:self
waitUntilDone:YES]; flags |= kAddedStreamsToRunLoop;
} return YES;
}

  

一、GCDAsyncSocket的核心就是dispatch_source_set_event_handler

1.accpet回调

            accept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, , socketQueue);

            int socketFD = socket4FD;
dispatch_source_t acceptSource = accept4Source; dispatch_source_set_event_handler(accept4Source, ^{ @autoreleasepool { LogVerbose(@"event4Block"); unsigned long i = ;
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, , socketQueue);
writeSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, , 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 > )
[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: maxLength: 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: tag:tag];
} - (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag
{
[self readDataToData:data withTimeout:timeout buffer:nil bufferOffset: 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] == ) {
LogWarn(@"Cannot read: [data length] == 0");
return;
}
if (offset > [buffer length]) {
LogWarn(@"Cannot read: offset > [buffer length]");
return;
}
if (maxLength > && 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:
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
}

4.runloop

第3月第1天 GCDAsyncSocket dispatch_source_set_event_handler runloop的更多相关文章

  1. 第2月第1天 GCDAsyncSocket dispatch_source_set_event_handler

    一.GCDAsyncSocket的核心就是dispatch_source_set_event_handler 1.accpet回调 accept4Source = dispatch_source_cr ...

  2. XMPP适配IPV6 (GCDAsyncSocket适配IPV6)

    苹果公司要求在6月1号之后上架Appstore的应用必须通过ipv6兼容测试. 最近到了八月份,开始发现新上架的app没有通过,查看了下原因,说没有适配IPV6. 首先在本地搭建一个IPV6的测试环境 ...

  3. 猖獗的假新闻:2017年1月1日起iOS的APP必须使用HTTPS

    一.假新闻如此猖獗 刚才一位老同事 打电话问:我们公司还是用的HTTP,马上就到2017年了,提交AppStore会被拒绝,怎么办? 公司里已经有很多人问过这个问题,回答一下: HTTP还是可以正常提 ...

  4. js获取给定月份的N个月后的日期

    1.在讲js获取给定月份的N个月后的日期之前,小颖先给大家讲下getFullYear().getYear()的区别. ①getYear() var d = new Date() console.log ...

  5. 张小龙宣布微信小程序1月9日发布,并回答了大家最关心的8个问题

    2016 年 12 月 28 日,张小龙在微信公开课 PRO 版的会场上,宣布了微信小程序的正式发布时间. 微信小程序将于 2017 年 1 月 9 号正式上线. 同时他解释称,小程序就像PC时代的网 ...

  6. 【代码笔记】iOS-获得当前的月的天数

    一,代码. #import "ViewController.h" @interface ViewController () @end @implementation ViewCon ...

  7. 怎样两个月完成Udacity Data Analyst Nanodegree

    在迷恋数据科学很久后,我决定要在MOOC网站上拿到一份Data Science的证书.美国三个MOOC网站,Udacity上的课程已经被分成了数个nanodegree,每个nanodegree都是目前 ...

  8. 我想立刻辞职,然后闭关学习编程语言,我给自己3个月时间学习C语言!这样行的通吗

    文章背景,回答提问:我想立刻辞职,然后闭关学习编程语言,我给自己3个月时间学习C语言!这样行的通吗? 我的建议是这样:1. 不要辞职.首先说,你对整个开发没有一个简单的了解,或一个系统的入门学习.换句 ...

  9. 【月入41万】Mono For Android中使用百度地图SDK

    借助于Mono For Android技术,.Net开发者也可以使用自己熟悉的C#语言以及.Net来开发Android应用.由于Mono For Android把Android SDK中绝大部分类库都 ...

随机推荐

  1. Essential Phone PH1官方刷机方法

    Essential Phone官方有两种包 一种是ota包,即sideload线刷使用的包.但此刷机方法只能ota升级,不能降级. 另一种是Images包,即fastboot线刷使用的包.这种方法可以 ...

  2. ceph radosgw-admin的操作

    常用操作: 生成一新用户: 在两个集群当中都创建相同的管理用户 radosgw-admin user create --uid=admin --display-name=admin --access_ ...

  3. BZOJ3899 仙人掌树的同构(圆方树+哈希)

    考虑建出圆方树.显然只有同一个点相连的某些子树同构会产生贡献.以重心为根后(若有两个任取一个即可),就只需要处理子树内部了. 如果子树的根是圆点,其相连的同构子树可以任意交换,方案数乘上同构子树数量的 ...

  4. ansible创建vmware虚拟机

    环境:vmware 虚拟化需求:如果业务部门一次提几十台甚至几百台虚拟机需求,一个个的手动创建肯定耗时 使用ansible vmware_guest 创建虚拟机,避免手动一台一台创建的纯手工 工作废话 ...

  5. python测试webservice接口

    1.下载库:https://pypi.python.org/pypi/suds-jurko 2.解压后,进入到解压目录,安装库:python3 setup.py install 3.测试获取手机归属地 ...

  6. cf609E Minimum Spanning Tree For Each Edge (kruskal+倍增Lca)

    先kruskal求出一个最小生成树,然后对于每条非树边(a,b),从树上找a到b路径上最大的边,来把它替换掉,就是包含这条边的最小生成树 #include<bits/stdc++.h> # ...

  7. POJ3287(BFS水题)

    Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...

  8. CF848E Days of Floral Colours——DP+多项式求逆/分治NTT

    官方题解:http://codeforces.com/blog/entry/54233 就是由简入繁 1.序列处理,只考虑一个半圆 2.环形处理(其实这个就是多了旋转同构) 然后基于分割线邻居的跨越与 ...

  9. A1039. Course List for Student

    Zhejiang University has 40000 students and provides 2500 courses. Now given the student name lists o ...

  10. asp 调用 vb(activex dll) ,参数传递(传引用)需要注意

    今天上午测试 vb 与 c(dll) 之间交互,传递参数的时候,没遇到什么太大的问题. 下午在asp中调用vb(activex dll)时, 在asp代码中传参数到 vb(dll)中时,遇到问题了. ...