嗨,根据这个答案,我写了子类,NSInputStream
它工作得很好。
现在事实证明,我有一个场景,我正在向服务器提供大量数据并防止其他服务饥饿,我需要控制提供数据的速度。因此,我通过以下条件改进了子类的功能:
- 当数据应该被推迟时,
hasBytesAvailable
返回NO
和读取尝试以读取的零字节结束 - 当可以发送数据时,
- read:maxLength:
允许一次读取一些最大数量的数据(默认为 2048)。 - 当
- read:maxLength:
返回读取的零字节时,计算所需的延迟并在延迟NSStreamEventHasBytesAvailable
事件发布之后。
这是代码的有趣部分(它与 C++ 混合):
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
if (![self isOpen]) {
return kOperationFailedReturnCode;
}
int delay = 0;
NSInteger readCount = (NSInteger)self.cppInputStream->Read(buffer, len, delay);
if (readCount<0) {
return kOperationFailedReturnCode;
}
LOGD("Stream") << __PRETTY_FUNCTION__
<< " len: " << len
<< " readCount: "<< readCount
<< " time: " << (int)(-[openDate timeIntervalSinceNow]*1000)
<< " delay: " << delay;
if (!self.cppInputStream->IsEOF()) {
if (delay==0)
{
[self enqueueEvent: NSStreamEventHasBytesAvailable];
} else {
NSTimer *timer = [NSTimer timerWithTimeInterval: delay*0.001
target: self
selector: @selector(notifyBytesAvailable:)
userInfo: nil
repeats: NO];
[self enumerateRunLoopsUsingBlock:^(CFRunLoopRef runLoop) {
CFRunLoopAddTimer(runLoop, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
}];
}
} else {
[self setStatus: NSStreamStatusAtEnd];
[self enqueueEvent: NSStreamEventEndEncountered];
}
return readCount;
}
- (void)notifyBytesAvailable: (NSTimer *)timer {
LOGD("Stream") << __PRETTY_FUNCTION__ << "notifyBytesAvailable time: " << (int)(-[openDate timeIntervalSinceNow]*1000);
[self enqueueEvent: NSStreamEventHasBytesAvailable];
}
- (BOOL)hasBytesAvailable {
bool result = self.cppInputStream->HasBytesAvaible();
LOGD("Stream") << __PRETTY_FUNCTION__ << ": " << result << " time: " << (int)(-[openDate timeIntervalSinceNow]*1000);
return result;
}
我为此写了一些测试,它奏效了。
当我将此流NSURLSession
用作 HTTP 请求的正文源时出现问题。从日志中我可以看到它NSURLSession
试图一次读取所有内容。在第一次阅读时,我返回有限部分的数据。之后立即NSURLSession
询问是否有可用的字节(我返回NO
)。一段时间后(例如 170 毫秒),我发送通知说字节现在可用但NSURLSession
不响应并且不调用我的流类的任何方法。
这是我在日志中看到的(运行一些测试时):
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper open]
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 1 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper read:maxLength:] len: 32768 readCount: 2048 time: 0 delay: 170
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:14990[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper hasBytesAvailable]: 0 time: 0
09:32:15161[0x7000002a0000] D/Stream: -[CSCoreFoundationCppInputStreamWrapper notifyBytesAvailable:]notifyBytesAvailable time: 171
其中时间是自流打开以来的毫秒数。
LooksNSURLSession
无法处理数据速率有限的输入流。还有其他人有类似的问题吗?或者有替代概念如何实现带宽管理NSURLSession
?