Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ba6bd76

Browse files
Merge pull request #8 from CodeAcmen/develop
Develop
2 parents 2a25b00 + 9e6552e commit ba6bd76

File tree

24 files changed

+1390
-505
lines changed

24 files changed

+1390
-505
lines changed

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
#### v1.0.0 核心能力:**生产级网络通信架构** | **企业级 VIPER 架构**
5555
#### v1.1.0 核心能力:**多维度指标监控、全链路追踪**
5656

57-
#### v1.2.0 核心能力:TLV协议扩展型增强
57+
#### v1.2.0 核心能力:TLV协议扩展性增强
5858

5959
---
6060

@@ -139,7 +139,7 @@ client.send(message: imageMessage) { error in
139139
- **v1.0.1**:修复了因libffi编译导致无法在模拟器运行的问题
140140
- **v1.1.0**:新增全链路追踪、关键指标采集(网络质量/成功率/延迟)并添加演示Demo,引入序列号分区机制,整体逻辑优化
141141
- **v1.2.0**:协议改造为TLV结构,支持协议无缝升级,整体逻辑重构,消息构造和解析逻辑发生本质变化,详见Doc
142-
- **v1.2.1**:完善了消息错误机制,遵循单一职责拆分了数据包解析、组装
142+
- **v1.2.1**:完善了消息错误机制,遵循单一职责拆分了数据包解析、组装,抽象了连接管理类,优化了握手交换协议版本信息逻辑
143143

144144
### 版本规划
145145

‎iOS-Network-Stack-Dive/ArchitectureExtensions/NetworkMonitor/Metrics/TJPConcreteSession+TJPMetrics.h‎

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// TJPConnectionManager+TJPMetrics.h
3+
// iOS-Network-Stack-Dive
4+
//
5+
// Created by 唐佳鹏 on 2025年5月15日.
6+
// 连接埋点
7+
8+
#import "TJPConnectionManager.h"
9+
10+
NS_ASSUME_NONNULL_BEGIN
11+
12+
@interface TJPConnectionManager (TJPMetrics)
13+
14+
@end
15+
16+
NS_ASSUME_NONNULL_END
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
//
2-
// TJPConcreteSession+TJPMetrics.m
2+
// TJPConnectionManager+TJPMetrics.m
33
// iOS-Network-Stack-Dive
44
//
5-
// Created by 唐佳鹏 on 2025/4/10.
5+
// Created by 唐佳鹏 on 2025/5/15.
66
//
77

8-
#import "TJPConcreteSession+TJPMetrics.h"
8+
#import "TJPConnectionManager+TJPMetrics.h"
99
#import <GCDAsyncSocket.h>
1010
#import <objc/runtime.h>
1111

1212
#import "TJPMetricsCollector.h"
1313

1414

15-
@implementation TJPConcreteSession (TJPMetrics)
15+
@implementation TJPConnectionManager (TJPMetrics)
1616
+ (void)initialize {
1717
[self enableMetricsMonitoring];
1818
}
@@ -76,12 +76,4 @@ - (void)metrics_socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host
7676
[[TJPMetricsCollector sharedInstance] incrementCounter:TJPMetricsKeyConnectionSuccess];
7777
[self metrics_socket:sock didConnectToHost:host port:port];
7878
}
79-
80-
81-
8279
@end
83-
84-
85-
86-
87-

‎iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/Tests/TJPMockFinalVersionTCPServer.m‎

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)t
109109

110110
// 处理消息
111111
switch (msgType) {
112-
case TJPMessageTypeNormalData: // TJPMessageTypeNormalData
112+
case TJPMessageTypeNormalData: // 普通数据消息
113113
{
114114
if (self.didReceiveDataHandler) {
115115
self.didReceiveDataHandler(payload, seq);
@@ -119,13 +119,61 @@ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)t
119119
break;
120120

121121

122-
case TJPMessageTypeHeartbeat: // TJPMessageTypeHeartbeat
122+
case TJPMessageTypeHeartbeat: // 心跳消息
123123
{
124124
if (self.didReceiveDataHandler) {
125125
self.didReceiveDataHandler(payload, seq);
126126
}
127127
[self sendHeartbeatACKForSequence:seq sessionId:sessionId toSocket:sock];
128128
}
129+
break;
130+
case TJPMessageTypeControl: // 控制消息
131+
{
132+
if (self.didReceiveDataHandler) {
133+
self.didReceiveDataHandler(payload, seq);
134+
}
135+
136+
//解析TLV数据,获取版本信息
137+
if (payload.length >= 12) {
138+
//Tag(2) + Length(4) + Value(2) + Flags(2)
139+
uint16_t tag;
140+
uint32_t length;
141+
uint16_t value;
142+
uint16_t flags;
143+
144+
const void *bytes = payload.bytes;
145+
memcpy(&tag, bytes, sizeof(uint16_t));
146+
memcpy(&length, bytes + 2, sizeof(uint32_t));
147+
memcpy(&value, bytes + 6, sizeof(uint16_t));
148+
memcpy(&flags, bytes + 8, sizeof(uint16_t));
149+
150+
// 转换网络字节序到主机字节序
151+
tag = ntohs(tag);
152+
length = ntohl(length);
153+
value = ntohs(value);
154+
flags = ntohs(flags);
155+
156+
NSLog(@"[MOCK SERVER] 版本协商:Tag=%u, Length=%u, Value=0x%04X, Flags=0x%04X",
157+
tag, length, value, flags);
158+
159+
if (tag == 0x0001) { // 版本标签
160+
uint8_t clientMajorVersion = (value >> 8) & 0xFF;
161+
uint8_t clientMinorVersion = value & 0xFF;
162+
163+
NSLog(@"[MOCK SERVER] 客户端版本: %u.%u", clientMajorVersion, clientMinorVersion);
164+
165+
NSLog(@"[MOCK SERVER] 客户端特性: %@", [self featureDescriptionWithFlags:flags]);
166+
167+
168+
// 发送版本协商响应
169+
[self sendVersionNegotiationResponseForSequence:seq sessionId:sessionId clientVersion:value
170+
supportedFeatures:flags toSocket:sock];
171+
}
172+
}
173+
174+
//发送控制消息ACK
175+
[self sendControlACKForSequence:seq sessionId:sessionId toSocket:sock];
176+
}
129177

130178
break;
131179

@@ -137,6 +185,18 @@ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)t
137185
[sock readDataWithTimeout:-1 tag:0];
138186
}
139187

188+
- (NSString *)featureDescriptionWithFlags:(uint16_t)flags {
189+
NSMutableString *desc = [NSMutableString string];
190+
191+
if (flags & 0x0001) [desc appendString:@"基本消息 "];
192+
if (flags & 0x0002) [desc appendString:@"加密 "];
193+
if (flags & 0x0004) [desc appendString:@"压缩 "];
194+
if (flags & 0x0008) [desc appendString:@"已读回执 "];
195+
if (flags & 0x0010) [desc appendString:@"群聊 "];
196+
197+
return desc.length > 0 ? desc : @"无特性";
198+
}
199+
140200
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
141201
[self.connectedSockets removeObject:sock];
142202
}
@@ -171,6 +231,33 @@ - (void)sendACKForSequence:(uint32_t)seq sessionId:(uint16_t)sessionId toSocket:
171231
[socket writeData:ackData withTimeout:-1 tag:0];
172232
}
173233

234+
- (void)sendControlACKForSequence:(uint32_t)seq sessionId:(uint16_t)sessionId toSocket:(GCDAsyncSocket *)socket {
235+
NSLog(@"[MOCK SERVER] 收到控制消息,序列号: %u", seq);
236+
237+
// 使用当前时间戳
238+
uint32_t currentTime = (uint32_t)[[NSDate date] timeIntervalSince1970];
239+
240+
TJPFinalAdavancedHeader reply = {0};
241+
reply.magic = htonl(kProtocolMagic);
242+
reply.version_major = kProtocolVersionMajor;
243+
reply.version_minor = kProtocolVersionMinor;
244+
reply.msgType = htons(TJPMessageTypeACK); // 仍然使用ACK类型,但可以考虑使用TJPMessageTypeControl
245+
reply.sequence = htonl(seq);
246+
reply.timestamp = htonl(currentTime);
247+
reply.encrypt_type = TJPEncryptTypeNone;
248+
reply.compress_type = TJPCompressTypeNone;
249+
reply.session_id = htons(sessionId);
250+
reply.bodyLength = 0;
251+
252+
// 没有数据体,checksum设为0
253+
reply.checksum = 0;
254+
255+
NSData *ackData = [NSData dataWithBytes:&reply length:sizeof(reply)];
256+
NSLog(@"[MOCK SERVER] 控制消息响应包字段:magic=0x%X, msgType=%hu, sequence=%u, timestamp=%u, sessionId=%hu",
257+
ntohl(reply.magic), ntohs(reply.msgType), ntohl(reply.sequence), ntohl(reply.timestamp), ntohs(reply.session_id));
258+
[socket writeData:ackData withTimeout:-1 tag:0];
259+
}
260+
174261

175262
- (void)sendHeartbeatACKForSequence:(uint32_t)seq sessionId:(uint16_t)sessionId toSocket:(GCDAsyncSocket *)socket {
176263
NSLog(@"[MOCK SERVER] 收到心跳包,序列号: %u", seq);
@@ -200,6 +287,61 @@ - (void)sendHeartbeatACKForSequence:(uint32_t)seq sessionId:(uint16_t)sessionId
200287
[socket writeData:ackData withTimeout:-1 tag:0];
201288
}
202289

290+
- (void)sendVersionNegotiationResponseForSequence:(uint32_t)seq sessionId:(uint16_t)sessionId clientVersion:(uint16_t)clientVersion supportedFeatures:(uint16_t)features toSocket:(GCDAsyncSocket *)socket {
291+
NSLog(@"[MOCK SERVER] 收到控制消息,序列号: %u", seq);
292+
293+
// 使用当前时间戳
294+
uint32_t currentTime = (uint32_t)[[NSDate date] timeIntervalSince1970];
295+
296+
// 服务器选择的版本和功能
297+
uint8_t serverMajorVersion = kProtocolVersionMajor;
298+
uint8_t serverMinorVersion = kProtocolVersionMinor;
299+
uint16_t serverVersion = (serverMajorVersion << 8) | serverMinorVersion;
300+
uint16_t agreedFeatures = features & 0x0003; // 仅支持客户端请求的部分功能
301+
302+
// 构建TLV数据
303+
NSMutableData *tlvData = [NSMutableData data];
304+
305+
// 版本协商响应TLV
306+
uint16_t versionResponseTag = htons(0x0002); // 响应标签
307+
uint32_t versionResponseLength = htonl(4);
308+
uint16_t versionResponseValue = htons(serverVersion);
309+
uint16_t agreedFeaturesValue = htons(agreedFeatures);
310+
311+
[tlvData appendBytes:&versionResponseTag length:sizeof(uint16_t)];
312+
[tlvData appendBytes:&versionResponseLength length:sizeof(uint32_t)];
313+
[tlvData appendBytes:&versionResponseValue length:sizeof(uint16_t)];
314+
[tlvData appendBytes:&agreedFeaturesValue length:sizeof(uint16_t)];
315+
316+
// 计算校验和
317+
uint32_t checksum = [TJPNetworkUtil crc32ForData:tlvData];
318+
319+
// 构建响应头
320+
TJPFinalAdavancedHeader responseHeader = {0};
321+
responseHeader.magic = htonl(kProtocolMagic);
322+
responseHeader.version_major = serverMajorVersion;
323+
responseHeader.version_minor = serverMinorVersion;
324+
responseHeader.msgType = htons(TJPMessageTypeControl);
325+
responseHeader.sequence = htonl(seq + 1); // 响应序列号+1
326+
responseHeader.timestamp = htonl(currentTime);
327+
responseHeader.encrypt_type = TJPEncryptTypeNone;
328+
responseHeader.compress_type = TJPCompressTypeNone;
329+
responseHeader.session_id = htons(sessionId);
330+
responseHeader.bodyLength = htonl((uint32_t)tlvData.length);
331+
responseHeader.checksum = htonl(checksum);
332+
333+
// 构建完整响应
334+
NSMutableData *responseData = [NSMutableData dataWithBytes:&responseHeader
335+
length:sizeof(responseHeader)];
336+
[responseData appendData:tlvData];
337+
338+
NSLog(@"[MOCK SERVER] 发送版本协商响应:服务器版本 %u.%u,协商功能 0x%04X",
339+
serverMajorVersion, serverMinorVersion, agreedFeatures);
340+
341+
[socket writeData:responseData withTimeout:-1 tag:0];
342+
343+
}
344+
203345

204346
//旧方法 已废弃目前单元测试在用 后续移除
205347
- (void)sendHeartbeatACKForSequence:(uint32_t)seq toSocket:(nonnull GCDAsyncSocket *)socket {

‎iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Bulider/TJPMessageBuilder.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
1515
/// 组装数据包
1616
+ (NSData *)buildPacketWithMessageType:(TJPMessageType)msgType sequence:(uint32_t)sequence payload:(NSData *)payload encryptType:(TJPEncryptType)encryptType compressType:(TJPCompressType)compressType sessionID:(NSString *)sessionID;
1717

18+
+ (uint16_t)sessionIDFromUUID:(NSString *)uuidString;
1819
@end
1920

2021
NS_ASSUME_NONNULL_END

‎iOS-Network-Stack-Dive/CoreNetworkStack/TransportLayer/V3_FinalProduct/Bulider/TJPMessageBuilder.m‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,11 @@ + (NSData *)buildPacketWithMessageType:(TJPMessageType)msgType sequence:(uint32_
4040
header.bodyLength = htonl((uint32_t)payload.length);
4141

4242
// 计算数据体的CRC32
43-
uint32_t checksum = [TJPNetworkUtil crc32ForData:payload];
44-
header.checksum = htonl(checksum); // 注意要转换为网络字节序
43+
uint32_t checksum = 0;
44+
if (payload.length > 0) {
45+
checksum = [TJPNetworkUtil crc32ForData:payload];
46+
}
47+
header.checksum = htonl(checksum); // 注意要转换为网络字节序
4548

4649
// 构建完整协议包
4750
NSMutableData *packet = [NSMutableData dataWithBytes:&header length:sizeof(header)];
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// TJPConnectionManager.h
3+
// iOS-Network-Stack-Dive
4+
//
5+
// Created by 唐佳鹏 on 2025年5月15日.
6+
//
7+
8+
#import <Foundation/Foundation.h>
9+
#import "TJPConnectionDelegate.h"
10+
#import "TJPCoreTypes.h"
11+
12+
13+
NS_ASSUME_NONNULL_BEGIN
14+
15+
@interface TJPConnectionManager : NSObject
16+
17+
@property (nonatomic, weak) id<TJPConnectionDelegate> delegate;
18+
/// 内部状态
19+
@property (nonatomic, readonly) TJPConnectionState internalState;
20+
/// 当前主机
21+
@property (nonatomic, readonly) NSString *currentHost;
22+
/// 当前端口
23+
@property (nonatomic, readonly) uint16_t currentPort;
24+
/// 断开原因
25+
@property (nonatomic, readonly) TJPDisconnectReason disconnectReason;
26+
/// 使用TLS 默认为NO方便单元测试
27+
@property (nonatomic, assign) BOOL useTLS;
28+
/// 连接时限窗口 默认30秒
29+
@property (nonatomic, assign) NSTimeInterval connectionTimeout;
30+
31+
/// 标志位
32+
@property (nonatomic, readonly) BOOL isConnected;
33+
@property (nonatomic, readonly) BOOL isConnecting;
34+
35+
/// 初始化方法
36+
- (instancetype)initWithDelegateQueue:(dispatch_queue_t)delegateQueue;
37+
/// 连接方法
38+
- (void)connectToHost:(NSString *)host port:(uint16_t)port;
39+
/// 断开连接方法
40+
- (void)disconnect;
41+
/// 断开连接原因
42+
- (void)disconnectWithReason:(TJPDisconnectReason)reason;
43+
/// 发送消息
44+
- (void)sendData:(NSData *)data;
45+
/// 带超时的发送消息
46+
- (void)sendData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
47+
/// 开始TLS
48+
- (void)startTLS:(NSDictionary *)settings;
49+
50+
/// 首次握手版本协商
51+
- (void)setVersionInfo:(uint8_t)majorVersion minorVersion:(uint8_t)minorVersion;
52+
53+
54+
@end
55+
56+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /