diff --git a/iOS-Network-Stack-Dive.xcworkspace/xcuserdata/aarongtang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/iOS-Network-Stack-Dive.xcworkspace/xcuserdata/aarongtang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 313a690..0565d50 100644 --- a/iOS-Network-Stack-Dive.xcworkspace/xcuserdata/aarongtang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/iOS-Network-Stack-Dive.xcworkspace/xcuserdata/aarongtang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -24,5 +24,21 @@ + + + + diff --git a/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/Collector/TJPMetricsCollector.m b/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/Collector/TJPMetricsCollector.m index f7db8c3..3cb143c 100644 --- a/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/Collector/TJPMetricsCollector.m +++ b/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/Collector/TJPMetricsCollector.m @@ -140,6 +140,8 @@ - (void)incrementCounter:(NSString *)key { } - (void)incrementCounter:(NSString *)key by:(NSUInteger)value { + if (!key) return; + [self performLocked:^{ // 特殊处理字节计数器 if ([key isEqualToString:TJPMetricsKeyBytesSend]) { @@ -268,10 +270,10 @@ - (void)recordError:(NSError *)error forKey:(NSString *)key { if (self.errors.count > 30) { [self.errors removeObjectsInRange:NSMakeRange(0, self.errors.count - 30)]; } - - // 增加错误计数 - [self incrementCounter:TJPMetricsKeyErrorCount]; }]; + + // 增加错误计数 + [self incrementCounter:TJPMetricsKeyErrorCount]; } - (NSArray *)recentErrors { @@ -323,9 +325,14 @@ - (void)recordEvent:(NSString *)eventName withParameters:(NSDictionary *)params #pragma mark - 线程安全操作 - (void)performLocked:(void (^)(void))block { + NSLog(@"准备获取锁 - 线程: %@", [NSThread currentThread]); os_unfair_lock_lock(&_lock); + NSLog(@"已获取锁 - 线程: %@", [NSThread currentThread]); block(); + NSLog(@"准备释放锁 - 线程: %@", [NSThread currentThread]); os_unfair_lock_unlock(&_lock); + NSLog(@"已释放锁 - 线程: %@", [NSThread currentThread]); + } diff --git a/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/TJPNetworkMonitorViewController.m b/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/TJPNetworkMonitorViewController.m index bc9ba2e..550b0b4 100644 --- a/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/TJPNetworkMonitorViewController.m +++ b/iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/TJPNetworkMonitorViewController.m @@ -68,16 +68,14 @@ - (void)setupNetwork { NSString *host = @"127.0.0.1"; uint16_t port = 12345; -// TJPNetworkConfig *config = [TJPNetworkConfig configWithHost:host port:port maxRetry:5 heartbeat:15.0]; -// -// // 2. 创建会话(中心协调器自动管理) -// self.session = [[TJPNetworkCoordinator shared] createSessionWithConfiguration:config]; -// -// // 3. 连接服务器 -// [self.session connectToHost:host port:port]; - + // 2. 创建TJPIMClient self.client = [TJPIMClient shared]; - [self.client connectToHost:host port:port]; + //可以进行相关client设置 + + // 3. 建立不同类型的连接 + [self.client connectToHost:host port:port forType:TJPSessionTypeChat]; +// [client connectToHost:@"media.example.com" port:8081 forType:TJPSessionTypeMedia]; + } - (void)setupLogTextView { @@ -99,14 +97,16 @@ - (void)setupSendMessageButton { // 发送消息按钮点击事件 - (void)sendMessageButtonTapped { - // 4. 发送消息 -// NSData *messageData = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding]; -// [self.session sendData:messageData]; -// NSLog(@"发送消息: %@", [[NSString alloc] initWithData:messageData encoding:NSUTF8StringEncoding]); - + // 4. 发送不同类型消息 TJPTextMessage *textMsg = [[TJPTextMessage alloc] initWithText:@"Hello World!!!!!111112223333"]; [self.client sendMessage:textMsg]; NSLog(@"发送消息: %@", textMsg.text); + // 发送消息 - 手动指定会话 + [self.client sendMessage:textMsg throughType:TJPSessionTypeChat]; + + // 发送消息 - 自动路由 +// TJPMediaMessage *mediaMsg = [[TJPMediaMessage alloc] initWithMediaId:@"12345"]; +// [self.client sendMessageWithAutoRoute:mediaMsg]; // 自动路由到媒体会话 } diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Connect/TJPConnectionManager.m b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Connect/TJPConnectionManager.m index a8e3025..8541688 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Connect/TJPConnectionManager.m +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Connect/TJPConnectionManager.m @@ -176,7 +176,6 @@ - (void)setVersionInfo:(uint8_t)majorVersion minorVersion:(uint8_t)minorVersion } #pragma mark - Private Methods - - (void)handleError:(NSError *)error withReason:(TJPDisconnectReason)reason { self.disconnectReason = reason; [self setInternalState:TJPConnectionStateDisconnected]; diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPConcreteSession.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPConcreteSession.h index e189c7f..c1073ad 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPConcreteSession.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPConcreteSession.h @@ -20,6 +20,8 @@ NS_ASSUME_NONNULL_BEGIN /// 独立的sessionId @property (nonatomic, copy) NSString *sessionId; +@property (nonatomic, assign) TJPSessionType sessionType; + /// 配置 @property (nonatomic, strong) TJPNetworkConfig *config; diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.h index b24fffd..a5be156 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.h @@ -19,10 +19,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) NSMapTable> *sessionMap; - +/// 网络状态 @property (nonatomic, strong) Reachability *reachability; - /// session专用队列 串行:增删改查操作 @property (nonatomic, strong) dispatch_queue_t sessionQueue; /// 解析专用队列 串行:数据解析专用 @@ -30,6 +29,9 @@ NS_ASSUME_NONNULL_BEGIN /// 监控专用队列 串行:网络监控相关 @property (nonatomic, strong) dispatch_queue_t monitorQueue; +/// 新增Session类型 为多路复用做支撑 +@property (nonatomic, strong) NSMutableDictionary *sessionTypeMap; + /// 单例 @@ -37,6 +39,12 @@ NS_ASSUME_NONNULL_BEGIN /// 创建会话方法 - (id)createSessionWithConfiguration:(TJPNetworkConfig *)config; +/// 通过类型创建会话方法 多路复用必须使用此方法 +- (id)createSessionWithConfiguration:(TJPNetworkConfig *)config type:(TJPSessionType)type; + +/// 新增默认session配置方法 +- (TJPNetworkConfig *)defaultConfigForSessionType:(TJPSessionType)type; + /// 统一更新所有会话状态 - (void)updateAllSessionsState:(TJPConnectState)state; /// 统一管理重连 diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.m b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.m index 710242c..591f690 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.m +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Container/TJPNetworkCoordinator.m @@ -46,7 +46,11 @@ - (instancetype)init { if (self = [super init]) { _networkChangeDebounceInterval = 2; _sessionMap = [NSMapTable strongToStrongObjectsMapTable]; + _sessionTypeMap = [NSMutableDictionary dictionary]; + + // 初始化队列 [self setupQueues]; + // 初始化网络监控 [self setupNetworkMonitoring]; } return self; @@ -54,12 +58,12 @@ - (instancetype)init { #pragma mark - Private Method - (void)setupQueues { - //串行队列,只处理会话 + // 串行队列,只处理会话 _sessionQueue = dispatch_queue_create("com.networkCoordinator.tjp.sessionQueue", DISPATCH_QUEUE_SERIAL); - //专用数据解析队列 并发高优先级 + // 专用数据解析队列 并发高优先级 _parseQueue = dispatch_queue_create("com.networkCoordinator.tjp.parseQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_set_target_queue(_parseQueue, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)); - //串行监控队列 + // 串行监控队列 _monitorQueue = dispatch_queue_create("com.networkCoordinator.tjp.monitorQueue", DISPATCH_QUEUE_SERIAL); dispatch_set_target_queue(_monitorQueue, dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)); } @@ -313,17 +317,38 @@ - (void)notifySessionsOfNetworkStatus:(BOOL)available { #pragma mark - Public Method - (id)createSessionWithConfiguration:(TJPNetworkConfig *)config { + return [self createSessionWithConfiguration:config type:TJPSessionTypeDefault]; +} + +- (id)createSessionWithConfiguration:(TJPNetworkConfig *)config type:(TJPSessionType)type { _currConfig = config; TJPConcreteSession *session = [[TJPConcreteSession alloc] initWithConfiguration:config]; + session.sessionType = type; session.delegate = self; + dispatch_barrier_async(self->_sessionQueue, ^{ [self.sessionMap setObject:session forKey:session.sessionId]; + // 记录会话类型映射 + self.sessionTypeMap[@(type)] = session.sessionId; + TJPLOG_INFO(@"Session created: %@, total: %lu", session.sessionId, (unsigned long)self.sessionMap.count); }); return session; } +// 根据类型获取会话 +- (id)sessionForType:(TJPSessionType)type { + __block id session = nil; + dispatch_sync(self->_sessionQueue, ^{ + NSString *sessionId = self.sessionTypeMap[@(type)]; + if (sessionId) { + session = [self.sessionMap objectForKey:sessionId]; + } + }); + return session; +} + - (void)updateAllSessionsState:(TJPConnectState)state { dispatch_barrier_async(self->_sessionQueue, ^{ @@ -339,6 +364,8 @@ - (void)updateAllSessionsState:(TJPConnectState)state { }); } + + - (void)removeSession:(id)session { dispatch_barrier_async(self->_sessionQueue, ^{ [self.sessionMap removeObjectForKey:session.sessionId]; @@ -363,6 +390,45 @@ - (void)scheduleReconnectForSession:(id)session { }); } +- (TJPNetworkConfig *)defaultConfigForSessionType:(TJPSessionType)type { + TJPNetworkConfig *config = [TJPNetworkConfig new]; + + switch (type) { + case TJPSessionTypeChat: + // 聊天会话配置 - 重视低延迟 + config.maxRetry = 5; + config.heartbeat = 15.0; + config.connectTimeout = 10.0; + break; + + case TJPSessionTypeMedia: + // 媒体会话配置 - 重视吞吐量 + config.maxRetry = 3; + config.heartbeat = 30.0; + config.connectTimeout = 20.0; + // 媒体会话可能需要更大的缓冲区 +// config.readBufferSize = 65536; + break; + + case TJPSessionTypeSignaling: + // 信令会话配置 - 极致低延迟 + config.maxRetry = 8; + config.heartbeat = 5.0; + config.connectTimeout = 5.0; + break; + + default: + // 默认配置 + config.maxRetry = 5; + config.heartbeat = 15.0; + config.connectTimeout = 15.0; + break; + } + + return config; +} + + #pragma mark - TJPSessionDelegate diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.h index 875d916..8215f55 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.h @@ -17,9 +17,12 @@ NS_ASSUME_NONNULL_BEGIN /// 连接方法 - (void)connectToHost:(NSString *)host port:(uint16_t)port; +- (void)connectToHost:(NSString *)host port:(uint16_t)port forType:(TJPSessionType)type; /// 发送消息 消息类型详见 TJPCoreTypes 头文件定义的 TJPContentType - (void)sendMessage:(id)message; +- (void)sendMessage:(id)message throughType:(TJPSessionType)type; + /// 断开连接 - (void)disconnect; diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.m b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.m index ac5f6d2..915d280 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.m +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/IMClient/TJPIMClient.m @@ -9,10 +9,16 @@ #import "TJPNetworkCoordinator.h" #import "TJPConcreteSession.h" #import "TJPNetworkConfig.h" +#import "TJPNetworkDefine.h" @interface TJPIMClient () -@property (nonatomic, strong) TJPConcreteSession *session; +// 单一会话移除 +//@property (nonatomic, strong) TJPConcreteSession *session; +// 添加通道字典 +@property (nonatomic, strong) NSMutableDictionary> *channels; +// 消息类型到会话类型的映射 +@property (nonatomic, strong) NSMutableDictionary *contentTypeToSessionType; @end @@ -25,18 +31,114 @@ + (instancetype)shared { return instance; } +- (instancetype)init { + if (self = [super init]) { + _channels = [NSMutableDictionary dictionary]; + _contentTypeToSessionType = [NSMutableDictionary dictionary]; + + // 设置默认映射 + [self setupDefaultRouting]; + } + return self; +} + + +#pragma mark - Public Method +//连接指定类型会话 +- (void)connectToHost:(NSString *)host port:(uint16_t)port forType:(TJPSessionType)type { + TJPNetworkConfig *config = [[TJPNetworkCoordinator shared] defaultConfigForSessionType:type]; + + // 设置主机和端口 + config.host = host; + config.port = port; + + // 获取会话 + id session = [[TJPNetworkCoordinator shared] createSessionWithConfiguration:config type:type]; + + // 保存到通道字典 + self.channels[@(type)] = session; + + [session connectToHost:host port:port]; +} + +// 兼容原有方法(使用默认会话类型) - (void)connectToHost:(NSString *)host port:(uint16_t)port { - TJPNetworkConfig *config = [TJPNetworkConfig configWithHost:host port:port maxRetry:5 heartbeat:15.0]; - self.session = (TJPConcreteSession *)[[TJPNetworkCoordinator shared] createSessionWithConfiguration:config]; - [self.session connectToHost:host port:port]; + [self connectToHost:host port:port forType:TJPSessionTypeDefault]; } -- (void)sendMessage:(id)message { +// 通过指定通道的session发送消息 +- (void)sendMessage:(id)message throughType:(TJPSessionType)type { + id session = self.channels[@(type)]; + + if (!session) { + TJPLOG_INFO(@"未找到类型为 %lu 的会话通道", (unsigned long)type); + return; + } + NSData *tlvData = [message tlvData]; - [self.session sendData:tlvData]; + [session sendData:tlvData]; +} + + +// 兼容原有方法(使用默认会话类型) +- (void)sendMessage:(id)message { + [self sendMessage:message throughType:TJPSessionTypeDefault]; +} + +// 自动路由版本的发送方法 +- (void)sendMessageWithAutoRoute:(id)message { + // 获取消息内容类型 + TJPContentType contentType = message.contentType; + + // 查找会话类型 + NSNumber *sessionTypeNum = self.contentTypeToSessionType[@(contentType)]; + TJPSessionType sessionType = sessionTypeNum ? [sessionTypeNum unsignedIntegerValue] : TJPSessionTypeDefault; + + // 调用发送方法 + [self sendMessage:message throughType:sessionType]; +} + +- (void)disconnectSessionType:(TJPSessionType)type { + id session = self.channels[@(type)]; + if (session) { + [session disconnectWithReason:TJPDisconnectReasonUserInitiated]; + [self.channels removeObjectForKey:@(type)]; + } } +// 兼容原有方法(断开默认会话) - (void)disconnect { - [self.session disconnectWithReason:TJPDisconnectReasonUserInitiated]; + [self disconnectSessionType:TJPSessionTypeDefault]; } + +- (void)disconnectAll { + for (NSNumber *key in [self.channels allKeys]) { + id session = self.channels[key]; + [session disconnectWithReason:TJPDisconnectReasonUserInitiated]; + } + [self.channels removeAllObjects]; +} + + +#pragma mark - Private Method +- (void)setupDefaultRouting { + //文本消息走聊天会话 媒体消息走媒体会话 因为对资源性要求不一样 + self.contentTypeToSessionType[@(TJPContentTypeText)] = @(TJPSessionTypeChat); + self.contentTypeToSessionType[@(TJPContentTypeImage)] = @(TJPSessionTypeMedia); + self.contentTypeToSessionType[@(TJPContentTypeAudio)] = @(TJPSessionTypeMedia); + self.contentTypeToSessionType[@(TJPContentTypeVideo)] = @(TJPSessionTypeMedia); + self.contentTypeToSessionType[@(TJPContentTypeFile)] = @(TJPSessionTypeMedia); + self.contentTypeToSessionType[@(TJPContentTypeLocation)] = @(TJPSessionTypeChat); + self.contentTypeToSessionType[@(TJPContentTypeCustom)] = @(TJPSessionTypeDefault); + + // 添加新的内容类型时,需更新映射表 +} + +// 配置路由方法 +- (void)configureRouting:(TJPContentType)contentType toSessionType:(TJPSessionType)sessionType { + self.contentTypeToSessionType[@(contentType)] = @(sessionType); +} + + + @end diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Protocol/TJPMessageProtocol.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Protocol/TJPMessageProtocol.h index 259fe0e..80e3f17 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Protocol/TJPMessageProtocol.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Protocol/TJPMessageProtocol.h @@ -6,12 +6,16 @@ // 消息接口 #import +#import "TJPCoreTypes.h" NS_ASSUME_NONNULL_BEGIN @protocol TJPMessageProtocol @required + +@property (nonatomic, readonly) TJPContentType contentType; + /// 消息类型 + (uint16_t)messageTag; /// TLV数据格式 diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPCoreTypes.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPCoreTypes.h index f6281dc..6cba318 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPCoreTypes.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPCoreTypes.h @@ -8,6 +8,13 @@ #ifndef TJPCoreTypes_h #define TJPCoreTypes_h +typedef NS_ENUM(NSUInteger, TJPSessionType) { + TJPSessionTypeDefault = 0, // 默认通用会话 + TJPSessionTypeChat = 1, // 聊天会话 + TJPSessionTypeMedia = 2, // 媒体传输会话 + TJPSessionTypeSignaling = 3 // 信令会话 +}; + // 协议支持的特性定义 typedef enum { // 基本消息能力 (必须支持) diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.h b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.h index 749c4a2..52a725b 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.h +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.h @@ -27,6 +27,9 @@ NS_ASSUME_NONNULL_BEGIN /// 基础延迟默认 2秒 @property (nonatomic, assign) NSTimeInterval baseDelay; +/// 连接超时 默认15秒 +@property (nonatomic, assign) NSTimeInterval connectTimeout; + /// 是否在服务器关闭连接后重连 @property (nonatomic, assign) BOOL shouldReconnectAfterServerClose; diff --git a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.m b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.m index 7cb17b7..90eed7b 100644 --- a/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.m +++ b/iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Utility/TJPNetworkConfig.m @@ -36,6 +36,7 @@ - (instancetype)initWithHost:(NSString *)host port:(uint16_t)port maxRetry:(NSUI _shouldReconnectAfterBackground = YES; _shouldReconnectAfterServerClose = NO; _useTLS = NO; + _connectTimeout = 15.0; // 默认指标设置