How to solve timeout issues caused by bad HTTP persistent connection?

前端 未结 3 1695
独厮守ぢ
独厮守ぢ 2021-02-06 09:12

I\'ve been struggling with an HTTP timeout issue recently. After more than one month of investigation I\'m quite sure that it is caused by bad HTTP persistent connections. Detai

3条回答
  •  醉梦人生
    2021-02-06 10:02

    Same issue here, iOS just try to reuse the connection after server drops it.

    Why CFNetwork is NOT Enough

    About two years ago, I switched to CFNetwork to workaround this issue, but recently I found it's not possible to implement SSL pinning with CFNetwork API. So now I'm considering go back to NSURLSession.

    The Workaround

    After some dig around, I found system will NOT reuse connections across NSURLSessions, so creating new sessions within period of time, should solve the issue.

    But I also found (at least on macOS): each connection made by NSURLSession can persistence last by 180 seconds, and that connection didn't close by release or reset the session, so you may need to implement some caching mechanism to avoid creating a lots of connections at the same time.

    Here is the simple mechanism I'm currently use:

    @interface HTTPSession : NSObject
    
    @property (nonatomic, strong) NSURLSession * urlSession;
    @property (nonatomic, assign) CFTimeInterval flushTime;
    
    @end
    
    + (NSURLSession *)reuseOrCreateSession
    {
        static NSMutableArray * sessions = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sessions = [NSMutableArray array];
        });
    
        const CFTimeInterval serverTimeoutSeconds = 10;
        const CFTimeInterval systemTimeoutSeconds = 40;
        CFTimeInterval now = CFAbsoluteTimeGetCurrent();
    
        HTTPSession * resultSession = nil;
        for (HTTPSession * session in sessions) {
            CFTimeInterval lifeTime = now - session.flushTime;
            if (lifeTime < serverTimeoutSeconds) {
                resultSession = session;
                break;
            }
            if (lifeTime > systemTimeoutSeconds) {
                resultSession = session;
                resultSession.flushTime = now;
                break;
            }
        }
    
        if (!resultSession) {
            resultSession = [HTTPSession new];
    
            NSURLSession * session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    
            // setup session
    
            resultSession.urlSession = session;
            resultSession.flushTime = now;
    
            [sessions addObject:resultSession];
        }
    
        return resultSession.urlSession;
    }
    

提交回复
热议问题