面试题答案
一键面试网络连接管理
- 复用连接:
- 在高并发场景下,频繁创建和销毁网络连接会消耗大量资源。通过维护一个连接池,对于不同的 P2P 文件传输任务,优先尝试复用已有的连接。例如,使用
NSURLSession
时,可以配置NSURLSessionConfiguration
的connectionProxyDictionary
等属性来控制连接行为,尽量保持连接的持续性。 - 对于 TCP 连接,可以设置
SO_KEEPALIVE
选项,让系统定期发送探测包以保持连接活跃,避免因长时间空闲而被中间网络设备关闭。在 Objective - C 中使用 BSD 套接字时,可通过如下代码设置:
int keepAlive = 1; setsockopt(socketFD, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive));
- 在高并发场景下,频繁创建和销毁网络连接会消耗大量资源。通过维护一个连接池,对于不同的 P2P 文件传输任务,优先尝试复用已有的连接。例如,使用
- 负载均衡:
- 如果有多个对等节点(Peer)可供选择进行文件传输,需要实现负载均衡策略。可以根据节点的带宽、当前连接数、响应时间等因素来选择最优的节点。例如,维护一个节点状态表,定期更新每个节点的上述信息。在选择节点时,优先选择带宽高、连接数少且响应时间短的节点。
- 可以使用加权随机算法来实现简单的负载均衡。为每个节点根据其性能指标分配一个权重,然后按照权重比例随机选择节点进行连接。
数据分块传输
- 合适的分块大小:
- 选择合适的数据分块大小对于优化传输性能至关重要。如果分块太小,会导致网络请求头开销相对较大,降低有效数据传输效率;如果分块太大,在网络不稳定时,一旦出现错误,需要重传的数据量也会较大。一般来说,可以根据网络带宽和文件类型进行动态调整。对于高速网络和大文件,分块大小可以设置在 16KB - 64KB 之间。例如,对于视频文件传输,在局域网高带宽环境下,可尝试设置 64KB 的分块大小。
- 在 Objective - C 中,可以通过
NSData
的subdataWithRange:
方法来获取数据分块。例如:
NSData *fileData = [NSData dataWithContentsOfFile:filePath]; NSUInteger chunkSize = 32 * 1024; for (NSUInteger i = 0; i < fileData.length; i += chunkSize) { NSUInteger length = MIN(chunkSize, fileData.length - i); NSData *chunk = [fileData subdataWithRange:NSMakeRange(i, length)]; // 进行分块传输 }
- 并发分块传输:
- 为了充分利用网络带宽,在高并发场景下,可以同时传输多个数据分块。使用 GCD(Grand Central Dispatch)来管理并发任务。例如,创建一个并发队列,将每个数据分块的传输任务添加到队列中。
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); for (NSData *chunk in chunkArray) { dispatch_async(concurrentQueue, ^{ // 执行分块传输操作 }); }
- 同时,要注意控制并发数,避免因过多的并发任务导致系统资源耗尽。可以通过设置信号量(Semaphore)来限制并发任务数量。例如,创建一个信号量,初始值为允许的最大并发数,在每个任务开始前获取信号量,任务完成后释放信号量。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(5); // 最大并发数为5 for (NSData *chunk in chunkArray) { dispatch_async(concurrentQueue, ^{ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 执行分块传输操作 dispatch_semaphore_signal(semaphore); }); }
错误处理
- 网络错误处理:
- 在网络传输过程中,可能会遇到各种网络错误,如连接超时、网络中断等。使用
NSURLSession
时,可以通过实现NSURLSessionDataDelegate
的相关方法来处理错误。例如,在URLSession:task:didCompleteWithError:
方法中处理任务完成时的错误:
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { if (error.code == NSURLErrorTimedOut) { // 处理连接超时错误,例如重新发起连接 } else if (error.code == NSURLErrorNetworkConnectionLost) { // 处理网络中断错误,尝试重新连接或等待网络恢复 } } }
- 对于 BSD 套接字,可通过
select
或epoll
等机制来检测套接字状态,及时发现并处理网络错误。例如,使用select
时,如果检测到套接字错误,可以关闭套接字并重新建立连接。
- 在网络传输过程中,可能会遇到各种网络错误,如连接超时、网络中断等。使用
- 数据校验与重传:
- 为了确保数据的完整性,在接收端需要对传输的数据进行校验。可以使用哈希算法,如 MD5、SHA - 1 等,在发送端对每个数据分块计算哈希值,并随数据分块一起发送。在接收端,对接收到的数据分块重新计算哈希值,并与发送端传来的哈希值进行比较。如果不一致,则认为数据传输有误,请求发送端重传该分块。
- 在 Objective - C 中,可以使用
CommonCrypto
框架来计算哈希值。例如,计算 MD5 哈希值的代码如下:
#import <CommonCrypto/CommonDigest.h> - (NSString *)md5HashForData:(NSData *)data { unsigned char digest[CC_MD5_DIGEST_LENGTH]; CC_MD5(data.bytes, (CC_LONG)data.length, digest); NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2]; for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { [output appendFormat:@"%02x", digest[i]]; } return output; }
- 当发现数据错误需要重传时,可以通过维护一个重传队列,将需要重传的数据分块添加到队列中,并按照一定的策略(如指数退避算法)进行重传。指数退避算法是指每次重传间隔时间按照指数增长,例如第一次重传间隔 1 秒,第二次间隔 2 秒,第三次间隔 4 秒等,以避免短时间内频繁重传导致网络拥塞。