Bandwidth Management iOS / OS X NSURLSession

Application

I have a very complicated application that uses several network services. Some of them require bandwidth and time (for example, SIP service), and some of them are more tolerant of poor Internet connection (for example, Power Point presentation).

Problem

Now there is the problem of starvation (one service may dominate the entire bandwidth).

Data acquisition was easily allowed. The data transfer rate is calculated for each service, and the application sends the required data transfer rate to the server, and the server controls the speed of incoming data.

The tough problem is to control the data transfer rate when sending data. To connect to the raw connector, this is quite simple. The output stream of the sockets simply terminates with a subclass of NSOutputStream , which delays the events of the HasSpaceAvailable stream, depending on how many bytes were written to the socket over a certain period of time.

Question

The question is, how to do it right for NSURLSession ? I could do the same trick for the HTTP body input stream that comes in the delegate method:

 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler 

but this approach does not take into account the HTTP frame (headers). For some service that will conduct intensive polling, an HTTP frame can be a significant part of the data sent. Thus, in order to properly control the data transfer rate, it is necessary to consider the HTTP frame. The problem is that there is no API that could help control the data rate for the entire HTTP protocol. I can see an API that allows you to manage only the resulting HTTP request array.

Update

I tried to use the needNewBodyStream API and it does not work. NSURLSession uses the supplied stream synchronously. Any attempts to split the data into pieces that may be delayed for sending lead to some strange errors, and the request is not sent at all.

So, I am looking for any alternative. The solution proposed in response: the own implementation of NSURLProtocol has many disadvantages:

  • a lot of complicated code that is not related to my instance of NSURLSession
  • problems to distinguish what services are available, so that the bandwidth assigns the request
  • this affects the whole application and I provide the framework

So I'm still looking for the best solution.

+7
ios objective-c swift nsurlsession macos
source share
1 answer

I am not 100% sure if it will work in your use case. I believe you might need to take a look at the NSURLSessionStreamTask API.

It seems to offer manual control over the number of bytes that you can write to the base socket (same as in your use case). Use readData: to read part of your input body data stream.

 /* 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; 

Then you can use writeData: to write this packet to your socket.

 /* 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; 

I'm not sure if it can solve your problem with HTTPHeader and Body data, which are different packages. It sounds like the right path to follow at the moment.

Hope this helps you.

+1
source share

All Articles