+ (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

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

  1. 第3月第1天 GCDAsyncSocket dispatch_source_set_event_handler runloop

    + (void)startCFStreamThreadIfNeeded { LogTrace(); static dispatch_once_t predicate; dispatch_once(&a ...

  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. SSH-Hibernate+Struts2+Spring的股票项目整合

    创建项目之前:我们需要导入我们需要的Hibernate和Struts2和Spring的相关架包.(博客自创,如有问题请留言博主,拒绝盗版,支持正版http://www.cnblogs.com/WuXu ...

  2. php导出EXCEL方法

    // 将数据表导出成 csv 格式文件并下载 // @param string $data:要导出的数据 // @param array $del:不导出的字段名,指定的字段数据不被导出 // @pa ...

  3. CSS实现进度条和订单进度条

    最近半个月为了期末考试,可要了学渣我半瓶血啊!今天本该好好复习的,可是状态不好,就随便找点乐子玩一玩,于是乎就想起之前面试时面试官给的一道题(见标题),那就弄点简单的小玩意给自己洗洗脑咯. 简单地效果 ...

  4. cf Round 603

    A.Alternative Thinking(思维) 给出一个01串,你可以取反其中一个连续子串,问取反后的01子串的最长非连续010101串的长度是多少. 我们随便翻一个连续子串,显然翻完之后,对于 ...

  5. Win10 UWP开发实现Bing翻译

    微软在WP上的发展从原来的Win7到Win8,Win8.1,到现在的Win10 UWP,什么是UWP,UWP即Windows 10 中的Universal Windows Platform简称.即Wi ...

  6. docfx预热中

    奋战了几个月,docfx终于有些像样了. 预览文档: http://aspnet.github.io/docfx/ 源代码正在准备开源中 Nuget包很快会发布 FAQ: Q: docfx是什么? A ...

  7. java用selenium库控制chrome

    一.简介 selenium是浏览器自动化工具,可以通过程序来控制浏览器行为,这就是selenium!你可以用它做任何你想做的事情.很多时候人们用它测试web应用,但selenium的用途绝不仅限于此. ...

  8. 非对称加密算法RSA

    RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年首次公布,当时他们 ...

  9. Node+Socketio实现消息群发功能

    注:本博文是作者原创,转载请注明出处. 在项目中时常会使用到socketio,今天我们就来实现Node+socketio实现群发消息功能, 项目源码:https://github.com/zhangx ...

  10. __delattr__\__delitem__

    class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): print(self.__dict__[ ...