iOS/OS X带宽管理NSURLSession

Mar*_*k R 8 macos objective-c ios nsurlsession swift

应用

我有非常复杂的应用程序,它使用多种网络服务.其中一些是带宽要求和时间关键(例如SIP服务),有些更容忍互联网连接不良(例如电源点显示).

问题

现在存在饥饿问题(一个服务可以支配整个带宽).

接收数据很容易解决.计算每个服务的数据速率,应用程序将所需的数据速率发送到服务器,服务器控制传入数据的速度.

困难的问题是在发送数据时控制数据的速度.对于原始套接字连接,这很容易.套接字输出流简单地由子类包装,子类NSOutputStream延迟流事件HasSpaceAvailable,具体取决于在某个时间单元中已经写入套接字的字节数.

问题是如何正确地做到这一点NSURLSession?我可以为委托方法中提供的HTTP正文的输入流做同样的技巧:

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
Run Code Online (Sandbox Code Playgroud)

但是这种方法不会考虑HTTP帧(标题).对于某些将进行密集轮询的服务,HTTP帧可以是发送数据的重要部分.因此,要正确控制数据速率,应考虑HTTP帧.问题是没有API可以帮助控制整个HTTP协议的数据速率.我可以看到API,它只允许控制HTTP请求体的数据.

更新

我试过使用API​​ needNewBodyStream,它不起作用.NSURLSession同步使用传递的流.任何将数据拆分成可能延迟发送的块的尝试都会导致一些奇怪的错误和请求根本不会被发送.

所以我正在寻找任何替代方案.答案中提出的解决方案:NSURLProtocol自己的实现有很多缺点:

  • 许多复杂的代码不会传递与我的NSURLSession实例相关的内容
  • 区分哪些服务的问题是哪个带宽桶分配请求
  • 这对整个应用程序有影响,我提供了一个框架

所以我仍在寻找更好的解决方案

Tar*_*agi 2

我不能 100% 确定它是否会在您的用例中发挥作用。我相信你可能需要看看NSURLSessionStreamTaskAPI。

它似乎提供了对可以写入底层套接字的字节数的手动控制(与您的用例相同)。用于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;
Run Code Online (Sandbox Code Playgroud)

然后你可以使用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;
Run Code Online (Sandbox Code Playgroud)

我不确定它是否能够解决您的问题HTTPHeaderBody数据是不同的数据包。这听起来是目前应该遵循的正确道路。

希望对您有帮助。