第2月第1天 GCDAsyncSocket dispatch_source_set_event_handler
+ (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的更多相关文章
- 第3月第1天 GCDAsyncSocket dispatch_source_set_event_handler runloop
+ (void)startCFStreamThreadIfNeeded { LogTrace(); static dispatch_once_t predicate; dispatch_once(&a ...
- XMPP适配IPV6 (GCDAsyncSocket适配IPV6)
苹果公司要求在6月1号之后上架Appstore的应用必须通过ipv6兼容测试. 最近到了八月份,开始发现新上架的app没有通过,查看了下原因,说没有适配IPV6. 首先在本地搭建一个IPV6的测试环境 ...
- 猖獗的假新闻:2017年1月1日起iOS的APP必须使用HTTPS
一.假新闻如此猖獗 刚才一位老同事 打电话问:我们公司还是用的HTTP,马上就到2017年了,提交AppStore会被拒绝,怎么办? 公司里已经有很多人问过这个问题,回答一下: HTTP还是可以正常提 ...
- js获取给定月份的N个月后的日期
1.在讲js获取给定月份的N个月后的日期之前,小颖先给大家讲下getFullYear().getYear()的区别. ①getYear() var d = new Date() console.log ...
- 张小龙宣布微信小程序1月9日发布,并回答了大家最关心的8个问题
2016 年 12 月 28 日,张小龙在微信公开课 PRO 版的会场上,宣布了微信小程序的正式发布时间. 微信小程序将于 2017 年 1 月 9 号正式上线. 同时他解释称,小程序就像PC时代的网 ...
- 【代码笔记】iOS-获得当前的月的天数
一,代码. #import "ViewController.h" @interface ViewController () @end @implementation ViewCon ...
- 怎样两个月完成Udacity Data Analyst Nanodegree
在迷恋数据科学很久后,我决定要在MOOC网站上拿到一份Data Science的证书.美国三个MOOC网站,Udacity上的课程已经被分成了数个nanodegree,每个nanodegree都是目前 ...
- 我想立刻辞职,然后闭关学习编程语言,我给自己3个月时间学习C语言!这样行的通吗
文章背景,回答提问:我想立刻辞职,然后闭关学习编程语言,我给自己3个月时间学习C语言!这样行的通吗? 我的建议是这样:1. 不要辞职.首先说,你对整个开发没有一个简单的了解,或一个系统的入门学习.换句 ...
- 【月入41万】Mono For Android中使用百度地图SDK
借助于Mono For Android技术,.Net开发者也可以使用自己熟悉的C#语言以及.Net来开发Android应用.由于Mono For Android把Android SDK中绝大部分类库都 ...
随机推荐
- python generator: next , sent(msg)区别
对于普通的生成器,第一个next调用,相当于启动生成器,会从生成器函数的第一行代码开始执行,直到第一次执行完yield语句(第4行)后,跳出生成器函数. 然后第二个next调用,进入生成器函数后,从y ...
- 3.bootstrap练习笔记-媒体内容
bootstrap练习笔记-多媒体对象 1.在bootstrap中,如果想存放内容,一种解决的方式就是利用media这个class 首先要设置一个div.container作为一个总的容器来存放内容 ...
- Spring框架总结
Spring(由Rod Johnson创建的一个开源框架) Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建.简单来说,Spr ...
- PAT 1040. 有几个PAT(25)
字符串APPAPT中包含了两个单词"PAT",其中第一个PAT是第2位(P),第4位(A),第6位(T):第二个PAT是第3位(P),第4位(A),第6位(T). 现给定字符串,问 ...
- 1264: [AHOI2006]基因匹配Match
1264: [AHOI2006]基因匹配Match Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 982 Solved: 635[Submit][S ...
- mac下打开FTP服务
MAC下打开FTP服务 周银辉 mac下一般用smb服务来进行远程文件访问,但要用FTP的话,高版本的mac os默认关掉了,可以用如下命令打开: sudo -s launchctl load -w ...
- Linux 进程间通讯详解四
msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); --功能:把一条消息添加到消息队列中 --参数 ...
- Caliburn.Micro学习笔记(一)----引导类和命名匹配规则
Caliburn.Micro学习笔记目录 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详 ...
- Css--深入学习之切角
本文是作者从别的网站和文章学习了解的知识,简单做了个笔记,想要学习更多的可以参考这里:[css进阶]伪元素的妙用--单标签之美,奇思妙想 带切角的矩形: 该图来源于(奇思妙想) Css代码: .not ...
- c#如何实现一个线程暂停,等待用户输入文本后继续运行?
using System; using System.Text; using System.Windows.Forms; using System.Threading; namespace Windo ...