iOS/OS X 带宽管理 NSURLSession
Posted
技术标签:
【中文标题】iOS/OS X 带宽管理 NSURLSession【英文标题】:iOS/OS X bandwidth management NSURLSession 【发布时间】:2016-03-30 20:00:45 【问题描述】:应用
我有一个非常复杂的应用程序,它使用多个网络服务。其中一些对带宽要求高且时间紧迫(例如 SIP 服务),而另一些则更能容忍糟糕的互联网连接(例如电源点演示)。
问题
现在有饥饿问题(一个服务可以控制整个带宽)。
接收数据已轻松解决。为每个服务计算数据速率,应用程序将所需的数据速率发送到服务器,服务器控制传入数据的速度。
难点是发送数据时控制数据的速度。
对于原始套接字连接,这很容易。套接字输出流由NSOutputStream
的子类简单地包装,它延迟流事件HasSpaceAvailable
,具体取决于在某个时间单位内写入套接字的字节数。
问题
问题是如何正确处理NSURLSession
?我可以对委托方法中传递的 HTTP 正文的输入流做同样的技巧:
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
但这种方法不会考虑 HTTP 帧(标头)。对于一些会进行密集轮询的服务,HTTP 帧可能是发送数据的重要部分。因此,要正确控制数据速率,应考虑 HTTP 帧。问题是没有 API 可以帮助控制整个 HTTP 协议的数据速率。我可以看到 API 只允许控制 HTTP 请求正文的数据。
更新
我尝试使用 API needNewBodyStream 但它不起作用。 NSURLSession 同步使用传递的流。任何将数据拆分为可能延迟发送的块的尝试都会导致一些奇怪的错误,并且根本不会发送请求。
所以我正在寻找任何替代方案。答案中提出的解决方案:自己的 NSURLProtocol 实现有很多缺点:
很多复杂的代码与我的 NSURLSession 实例不相关 区分什么是服务的问题是向哪个带宽桶分配请求 这会对整个应用程序产生影响,我正在提供一个框架所以我还在寻找更好的解决方案
【问题讨论】:
【参考方案1】:我不能 100% 确定它是否适用于您的用例。我相信你可能需要看看NSURLSessionStreamTask
API。
它似乎可以手动控制您可以写入底层套接字的字节数(与您的用例相同)。使用readData:
读取输入正文数据流的一部分。
/* Read minBytes, or at most maxBytes bytes and invoke the completion
* handler on the sessions delegate queue with the data or an error.
* If an error occurs, any outstanding reads will also fail, and new
* read requests will error out immediately.
*/
- (void)readDataOfMinLength:(NSUInteger)minBytes maxLength:(NSUInteger)maxBytes timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSData * __nullable data, BOOL atEOF, NSError * __nullable error))completionHandler;
然后你可以使用writeData:
将这个数据包写入你的套接字。
/* Write the data completely to the underlying socket. If all the
* bytes have not been written by the timeout, a timeout error will
* occur. Note that invocation of the completion handler does not
* guarantee that the remote side has received all the bytes, only
* that they have been written to the kernel.
*/
- (void)writeData:(NSData *)data timeout:(NSTimeInterval)timeout completionHandler:(void (^) (NSError * __nullable error))completionHandler;
我不确定它是否能够解决HTTPHeader
和Body
数据是不同数据包的问题。这听起来是目前应该遵循的正确道路。
希望对你有帮助。
【讨论】:
看起来很有趣。问题是我必须支持 ios 8 和 OS X 10.10(此 API 自 iOS 9 和 OS X 10.11 起可用)。我还是会调查的。感谢您的提示。 最后有结论了吗?我还需要通过 NSURLSession 理想地实现带宽限制。或者,here 的答案是建议使用较低级别的 API 或应用内 Web 代理,但每个选项都需要大量工作才能完成工作。以上是关于iOS/OS X 带宽管理 NSURLSession的主要内容,如果未能解决你的问题,请参考以下文章
我应该在 iOS/OS X 应用程序中在哪里初始化我的单例?