gpt4 book ai didi

ios - 慢速NSInputStream传递的NSURLSession请求体(带宽管理)

转载 作者:行者123 更新时间:2023-11-29 11:59:35 25 4
gpt4 key购买 nike

您好,基于 this answer我编写了 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

其中时间是自流打开以来的毫秒数。

看起来 NSURLSession 无法处理数据速率有限的输入流。还有其他人有类似的问题吗?或者有替代概念如何在 NSURLSession 上实现带宽管理?

最佳答案

我可以支持的解决方案是:

  1. 使用来自 iOS9 和 OSX10.11 的 NSURLSessionStreamTask。
  2. 改用 ASIHTTPRequest。

关于ios - 慢速NSInputStream传递的NSURLSession请求体(带宽管理),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37549895/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com