我们这里以原生的NSURLSession请求为例

首先是继承代理然后初始化请求配置,创建请求方法

这里请求方法必须用GET请求维持长链接的通道不断开(这里的不断开是相对的 并不是绝对的不断开 只是跟普通的HTTP请求完成不同 该长链接连接之后 正常情况下 会一直保持连接状态 直到一方主动断开)

<NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDataDelegate>
@property (nonatomic, assign) BOOL isConnected; // 长链接连接标识

// 创建长链接
- (void)createLongConnection {
  if (self.isConnected) {
    NSLog(@"长链接正常连接 无需要重新创建连接");
    return;
  }
    // 创建网络请求配置
    NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.urlSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSURL *url = [NSURL URLWithString:@"requestUrl"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:NETWORK_TIME_OUT];
    // 设置向服务器发送json格式数据
    [request setValue:@"application/json; charset=utf-8;" forHTTPHeaderField:@"Content-Type"];
    request.HTTPShouldUsePipelining = YES;
    request.HTTPMethod = @"GET";

    self.longConnectDataTask = [self.urlSession dataTaskWithRequest:request];
    [self.longConnectDataTask resume];

    // 开启长链接的心跳定时器
    __weak typeof(self) weakSelf = self;;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:NUMBER_TEN repeats:YES block:^(NSTimer * _Nonnull timer) {
        // 长链接检测
        [weakSelf checkLongConnectionStatus];
    }];
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

虽然此链接正常情况下 不会断开 稳定性也很高 但是为了保证业务的顺利进行 还是要自己加上定时的心跳检测 远端的心跳检测在网络资源里面占有比例非常高 建议合理的控制心跳的间隔时间

// 长链接网络状态检测
- (void)checkLongConnectionStatus {
    // 创建网络请求配置
    NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSURL *url = [NSURL URLWithString:@"requestUrl"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置向服务器发送json格式数据
    [request addValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    request.timeoutInterval = NETWORK_TIME_OUT;
    request.HTTPMethod = @"GET";

    self.checkStatusDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSHTTPURLResponse *statusReponse = (NSHTTPURLResponse *)response;
        if (statusReponse.statusCode == NEWTORK_STATUSCODE_SUCCESS) {
            // 长链接连接成功
            NSLog(@"长链接连接成功");
            self.isConnected = YES;
        } else {
            NSLog(@"长链接请求失败");
            // 防止多次创建长链接 保持只有一个长链接请求 手动停止task也会走到这个里面 需要做判断处理 完全释放 防止重新创建新的长链接
            if (self.isEnableCreate) {
                self.isConnected = NO;
                [self createLongConnection];
            }
        }
    }];
    [self.checkStatusDataTask resume];
}

NSURLSession 代理方法

#pragma mark - NSURLSession 代理方法
- (void)URLSession:(NSURLSession *)session
              dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveResponse:(NSURLResponse *)response
     completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
    // 允许网络继续请求
    completionHandler(NSURLSessionResponseAllow);
    NSHTTPURLResponse *statusReponse = (NSHTTPURLResponse *)response;
    if (statusReponse.statusCode == 200) {
        // 长链接连接成功 同时立即拉取一次最新的配置
        NSLog(@"长链接创建请求成功");
        self.isConnected = YES;
    		// 做其他业务逻辑
			
    }
}
completionHandler(NSURLSessionResponseAllow);

此方法是整个长链接过程中最核心的地方 它能保证数据的多次接收 所以一定要加上 否则后续会出现接收不到数据的情况,我在这里也踩了坑

处理长链接数据接收

以下操作是对接收的数据进行转义或者是取出多余的空格或者换行符号 如果不涉及可以不进行此操作 直接解析数据

string = [string
    stringByTrimmingCharactersInSet:[NSCharacterSet
                                        whitespaceAndNewlineCharacterSet]];
string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@""];
string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];

// 处理长连接收到的数据, 当前方法的调用在主线程中
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    if (!data) {
        NSLog(@"数据为空");
        return;
    }

    NSString *string = [[NSString alloc] initWithData:data
                                             encoding:NSUTF8StringEncoding];
    // 处理消息中可能出现的多余的换行符 空格符号
    string = [string
        stringByTrimmingCharactersInSet:[NSCharacterSet
                                            whitespaceAndNewlineCharacterSet]];
    string = [string stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    string = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    // 消息判空
    if [string.lenght == 0) {
        return;
    }
	// 处理数据
    
}

iOS HTTP长链接 需要使用代理的方式进行请求 默认AFN和NSUrlSession方式的回调请求是不能维持长链接的 连接上之后 会马上断开 导致后续无法 继续发送和接收数据,所以个人建议这里根据业务需求 可以自定义网络请求类