Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 79 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,49 +68,53 @@
---

##### NetworkManagerFinal(企业级多路复用)
**日均10w+连接验证 | 单元测试覆盖率>90%**
**日均10w+消息真实验证 | 单元测试覆盖率>90%**
- **架构亮点**
- **中心协调器**:动态扩容 + 故障隔离
- **会话自治模型**:独立状态机 + 自适应心跳
- **安全协议栈**:二进制协议设计 + TLS加密
- **安全协议栈**:二进制协议设计(定长头+TLV) + TLS加密
---
**Objective-C 接入示例**

```Objc
// 1. 初始化配置
NSString *host = @"127.0.0.1";
uint16_t port = 12345;
TJPNetworkConfig *config = [TJPNetworkConfig configWithHost:host port:port maxRetry:5 heartbeat:15.0];

// 2. 创建会话(中心协调器自动管理)
TJPConcreteSession *session = [[TJPNetworkCoordinator shared] createSessionWithConfiguration:config];

// 3. 连接服务器
[self.session connectToHost:host port:port];

// 4. 发送消息
NSData *messageData = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding];
[session sendData:messageData];
// 0. 在AppDelegate中添加
[TJPMessageFactory load];
// 1. 初始化客户端
TJPIMClient *client = [TJPIMClient shared];

// 2. 连接服务器(自动处理重连和心跳)
[client connectToHost:@"im.example.com" port:8080];

// 3. 创建文本消息(自动处理TLV序列化)
TJPTextMessage *textMsg = [TJPTextMessage messageWithText:@"Hello World"];

// 4. 发送消息(自动路由到最佳会话)
[client sendMessage:textMsg completion:^(NSError *error) {
if (!error) {
NSLog(@"消息已成功送达");
}
}];
```

**Swift 接入示例**

```Swift
// 1. 初始化配置
let host = "127.0.0.1"
let port: UInt16 = 12345
let config = TJPNetworkConfig(host: host, port: port, maxRetry: 5, heartbeat: 15.0)

// 2. 创建会话(中心协调器自动管理)
let session = TJPNetworkCoordinator.shared.createSession(with: config)

// 3. 连接服务器
session.connectToHost(host, port: port)

// 4. 发送消息
let message = "Hello World"
if let messageData = message.data(using: .utf8) {
session.sendData(messageData)
// 0. 在AppDelegate中添加
TJPMessageFactory.load
// 1. 获取客户端实例
let client = TJPIMClient.shared

// 2. 连接服务器(自动处理网络切换)
client.connect(host: "im.example.com", port: 8080)

// 3. 构造多媒体消息(自动压缩和格式转换)
let imageMessage = TJPImageMessage(image: UIImage(named: "avatar")!,
quality: .high)

// 4. 发送消息(自动重试和QoS保证)
client.send(message: imageMessage) { error in
guard error == nil else { return }
print("图片消息已确认接收")
}
```
##### 企业级 VIPER 架构体系
Expand All @@ -132,20 +136,21 @@ if let messageData = message.data(using: .utf8) {
- **v1.0.0**:网络框架基础核心功能基本完成、生产级VIPER架构演示完成
- **v1.0.1**:修复了因libffi编译导致无法在模拟器运行的问题
- **v1.1.0**:新增全链路追踪、关键指标采集(网络质量/成功率/延迟)并添加演示Demo,引入序列号分区机制,整体逻辑优化
- **v1.2.0**:协议改造为TLV结构,支持协议无缝升级,整体逻辑重构,消息构造和解析逻辑发生本质变化,详见Doc

### 版本规划

#### 🔜v1.2.0(开发中) - 长连接优化
#### 🔜v1.3.0(开发中) - 长连接优化
- **心跳保活增强**:运营商NAT超时适配
- **防拦截策略**:运营商级心跳包伪装
- **连接保持**:智能心跳间隔动态调整

#### v1.3.0(规划中) - 性能升级
#### v1.4.0(规划中) - 性能升级
- **连接池优化**:智能资源分配
- **分包策略升级**:大文件分片传输
- **QoS保障**:流量优先级控制

#### v1.4.0(规划中) - 极端场景优化
#### v1.5.0(规划中) - 极端场景优化
- **弱网对抗**:智能降级策略
- **错误恢复**:多级故障回滚
- **协议演进**:可靠UDP传输
Expand All @@ -165,28 +170,46 @@ if let messageData = message.data(using: .utf8) {
## 核心实现
Socket通信模块架构
```
+--------------------------+
| Network Layer |
| (CocoaAsyncSocket wrapper)|
+--------------------------+
|
v
+--------------------------+
| SocketManager |
| (Connection, Heartbeat) |
+--------------------------+
|
v
+--------------------------+
| Message Handler |
| (Message Parsing, Packets)|
+--------------------------+
|
v
+--------------------------+
| Protocol Layer |
| (Custom Protocol Logic) |
+--------------------------+
+---------------------------------------------------+
| 应用层 |
| 使用统一API管理网络通信 |
+---------------------------------------------------+
|
v
+---------------------------------------------------+
| TJPIMClient |
| (门面模式: 高级API + 内部适配器管理 + 代理分发) |
+---------------------------------------------------+
|
+---------+---------+
| |
v v
+-------------------------+ +-------------------------+
| TJPContentSessionAdapter| | TJPConcreteSession |
| (内容编解码与代理适配) | | (底层连接管理) |
+-------------------------+ +-------------------------+
|
v
+-------------------------+
| TJPNetworkCoordinator |
| (多会话协调与全局网络管理) |
+-------------------------+
|
v
+-------------------------+
| GCDAsyncSocket |
| (底层套接字通信) |
+-------------------------+
```
### TLV数据区格式
- **Tag**:业务标识(如 0x1001=用户ID),大端字节序。
- **Length**:Value 部分长度(不含 Tag 和 Length),大端字节序。
- **Value**:原始数据或嵌套 TLV(用保留 Tag 0xFFFF 标记)。
```
+------+----------+--------+
| Tag | Length | Value |
| 2字节| 4字节 | N字节 |
+------+----------+--------+
```

### 完整TCP状态机实现
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#import "TJPMockFinalVersionTCPServer.h"
#import "TJPMetricsConsoleReporter.h"

#import "TJPIMClient.h"
#import "TJPTextMessage.h"


@interface TJPNetworkMonitorViewController ()

Expand All @@ -25,6 +28,9 @@ @interface TJPNetworkMonitorViewController ()
@property (nonatomic, strong) UITextView *logTextView;


@property (nonatomic, strong) TJPIMClient *client;


@end

@implementation TJPNetworkMonitorViewController
Expand All @@ -46,6 +52,13 @@ - (void)viewDidLoad {
}];
}

- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];

[self.mockServer stop];
[self.session disconnect];
}

- (void)setupNetwork {
// 初始化模拟服务器
self.mockServer = [[TJPMockFinalVersionTCPServer alloc] init];
Expand All @@ -55,13 +68,17 @@ - (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];
// 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];

self.client = [TJPIMClient shared];
[self.client connectToHost:host port:port];

// 3. 连接服务器
[self.session connectToHost:host port:port];

}

Expand All @@ -85,9 +102,13 @@ - (void)setupSendMessageButton {
// 发送消息按钮点击事件
- (void)sendMessageButtonTapped {
// 4. 发送消息
NSData *messageData = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding];
[self.session sendData:messageData];
NSLog(@"发送消息: %@", [[NSString alloc] initWithData:messageData encoding:NSUTF8StringEncoding]);
// NSData *messageData = [@"Hello World" dataUsingEncoding:NSUTF8StringEncoding];
// [self.session sendData:messageData];
// NSLog(@"发送消息: %@", [[NSString alloc] initWithData:messageData encoding:NSUTF8StringEncoding]);

TJPTextMessage *textMsg = [[TJPTextMessage alloc] initWithText:@"Hello World!!!!!111112223333"];
[self.client sendMessage:textMsg];
NSLog(@"发送消息: %@", textMsg.text);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// TJPConcreteSession+TJPMessageAdapter.h
// iOS-Network-Stack-Dive
//
// Created by 唐佳鹏 on 2025/5/13.
//

#import "TJPConcreteSession.h"
#import "TJPMessage.h"

NS_ASSUME_NONNULL_BEGIN

@interface TJPConcreteSession (TJPMessageAdapter)

/// 发送消息
- (void)sendMessage:(id<TJPMessage>)message;


@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// TJPConcreteSession+TJPMessageAdapter.m
// iOS-Network-Stack-Dive
//
// Created by 唐佳鹏 on 2025/5/13.
//

#import "TJPConcreteSession+TJPMessageAdapter.h"

@implementation TJPConcreteSession (TJPMessageAdapter)

- (void)sendMessage:(id<TJPMessage>)message {
NSData *tlvData = [message tlvData];
[self sendData:tlvData];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ - (void)setupStateMachine {
TJPLOG_INFO(@"会话 %@ 状态变化: %@ -> %@", strongSelf.sessionId, oldState, newState);

// 通知代理
if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(session:stateChanged:)]) {
if (strongSelf.delegate && [strongSelf.delegate respondsToSelector:@selector(session:didChangeState:)]) {
dispatch_async(dispatch_get_main_queue(), ^{
[strongSelf.delegate session:strongSelf stateChanged:newState];
[strongSelf.delegate session:strongSelf didChangeState:newState];
});
}

Expand Down Expand Up @@ -640,8 +640,8 @@ - (void)processReceivedPacket:(TJPParsedPacket *)packet {
//处理普通数据包
- (void)handleDataPacket:(TJPParsedPacket *)packet {
TJPLOG_INFO(@"接收到 普通消息 数据包并进行处理");
if (self.delegate && [self.delegate respondsToSelector:@selector(session:didReceiveData:)]) {
[self.delegate session:self didReceiveData:packet.payload];
if (self.delegate && [self.delegate respondsToSelector:@selector(session:didReceiveRawData:)]) {
[self.delegate session:self didReceiveRawData:packet.payload];
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// TJPIMClient.h
// iOS-Network-Stack-Dive
//
// Created by 唐佳鹏 on 2025/5/13.
//

#import <Foundation/Foundation.h>
#import "TJPMessage.h"

NS_ASSUME_NONNULL_BEGIN

@interface TJPIMClient : NSObject

/// 单例类
+ (instancetype)shared;

/// 连接方法
- (void)connectToHost:(NSString *)host port:(uint16_t)port;

/// 发送消息
- (void)sendMessage:(id<TJPMessage>)message;

/// 断开连接
- (void)disconnect;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// TJPIMClient.m
// iOS-Network-Stack-Dive
//
// Created by 唐佳鹏 on 2025/5/13.
//

#import "TJPIMClient.h"
#import "TJPNetworkCoordinator.h"
#import "TJPConcreteSession.h"
#import "TJPNetworkConfig.h"


@interface TJPIMClient ()
@property (nonatomic, strong) TJPConcreteSession *session;


@end

@implementation TJPIMClient
+ (instancetype)shared {
static TJPIMClient *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; });
return instance;
}

- (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];
}

- (void)sendMessage:(id<TJPMessage>)message {
NSData *tlvData = [message tlvData];
[self.session sendData:tlvData];
}

- (void)disconnect {
[self.session disconnectWithReason:TJPDisconnectReasonUserInitiated];
}
@end
Loading