@pixelhue/event-controller-sdk 0.0.1 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/packages/tcp/ConnectManager.d.ts +1 -2
- package/dist/packages/tcp/ConnectManager.js +2 -3
- package/dist/packages/tcp/QueueManager.d.ts +0 -1
- package/dist/packages/tcp/QueueManager.js +9 -14
- package/dist/packages/tcp/SocketWrapper.d.ts +13 -3
- package/dist/packages/tcp/SocketWrapper.js +68 -28
- package/dist/packages/tcp/constants.d.ts +0 -1
- package/dist/packages/tcp/constants.js +0 -1
- package/dist/packages/tcp/discoveryService.d.ts +0 -1
- package/dist/packages/tcp/discoveryService.js +0 -1
- package/dist/packages/tcp/protocolHandler.d.ts +0 -1
- package/dist/packages/tcp/protocolHandler.js +2 -2
- package/dist/packages/tcp/tcpWrapper.d.ts +27 -4
- package/dist/packages/tcp/tcpWrapper.js +106 -50
- package/dist/packages/tcp/types.d.ts +0 -1
- package/dist/packages/tcp/types.js +0 -1
- package/dist/packages/tcp/utils.d.ts +0 -1
- package/dist/packages/tcp/utils.js +0 -1
- package/package.json +87 -82
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/packages/tcp/ConnectManager.d.ts.map +0 -1
- package/dist/packages/tcp/ConnectManager.js.map +0 -1
- package/dist/packages/tcp/QueueManager.d.ts.map +0 -1
- package/dist/packages/tcp/QueueManager.js.map +0 -1
- package/dist/packages/tcp/SocketWrapper.d.ts.map +0 -1
- package/dist/packages/tcp/SocketWrapper.js.map +0 -1
- package/dist/packages/tcp/constants.d.ts.map +0 -1
- package/dist/packages/tcp/constants.js.map +0 -1
- package/dist/packages/tcp/demo.d.ts +0 -3
- package/dist/packages/tcp/demo.d.ts.map +0 -1
- package/dist/packages/tcp/demo.js +0 -164
- package/dist/packages/tcp/demo.js.map +0 -1
- package/dist/packages/tcp/discoveryService.d.ts.map +0 -1
- package/dist/packages/tcp/discoveryService.js.map +0 -1
- package/dist/packages/tcp/protocolHandler.d.ts.map +0 -1
- package/dist/packages/tcp/protocolHandler.js.map +0 -1
- package/dist/packages/tcp/tcpWrapper.d.ts.map +0 -1
- package/dist/packages/tcp/tcpWrapper.js.map +0 -1
- package/dist/packages/tcp/test-build-parse-debug.d.ts +0 -2
- package/dist/packages/tcp/test-build-parse-debug.d.ts.map +0 -1
- package/dist/packages/tcp/test-build-parse-debug.js +0 -73
- package/dist/packages/tcp/test-build-parse-debug.js.map +0 -1
- package/dist/packages/tcp/test-packet-split.d.ts +0 -43
- package/dist/packages/tcp/test-packet-split.d.ts.map +0 -1
- package/dist/packages/tcp/test-packet-split.js +0 -417
- package/dist/packages/tcp/test-packet-split.js.map +0 -1
- package/dist/packages/tcp/test-protocol-handler.d.ts +0 -6
- package/dist/packages/tcp/test-protocol-handler.d.ts.map +0 -1
- package/dist/packages/tcp/test-protocol-handler.js +0 -225
- package/dist/packages/tcp/test-protocol-handler.js.map +0 -1
- package/dist/packages/tcp/test-server.d.ts +0 -54
- package/dist/packages/tcp/test-server.d.ts.map +0 -1
- package/dist/packages/tcp/test-server.js +0 -412
- package/dist/packages/tcp/test-server.js.map +0 -1
- package/dist/packages/tcp/types.d.ts.map +0 -1
- package/dist/packages/tcp/types.js.map +0 -1
- package/dist/packages/tcp/utils.d.ts.map +0 -1
- package/dist/packages/tcp/utils.js.map +0 -1
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
// ALL_CODE_LINE: 462
|
|
2
|
-
// AI_CODE_LINE: 462
|
|
3
|
-
import * as net from 'net';
|
|
4
|
-
import { ProtocolHandler } from './protocolHandler.js';
|
|
5
|
-
class TestTCPServer {
|
|
6
|
-
server = null;
|
|
7
|
-
clients = new Map();
|
|
8
|
-
port;
|
|
9
|
-
host;
|
|
10
|
-
protocolHandler;
|
|
11
|
-
/** 预设的测试数据包(十六进制) */
|
|
12
|
-
testDataPacket;
|
|
13
|
-
constructor(port = 8080, host = '127.0.0.1') {
|
|
14
|
-
this.port = port;
|
|
15
|
-
this.host = host;
|
|
16
|
-
this.protocolHandler = new ProtocolHandler();
|
|
17
|
-
// 标准测试数据包(使用 ProtocolHandler.build 生成)
|
|
18
|
-
// 包含完整的 Frame Head、Request Head 和 TLV 数据,符合协议规范
|
|
19
|
-
this.testDataPacket = Buffer.from('4E4F56410101000000000000000000005B0079796B20010000000100000000001030500000001D007B22736571223A302C22736E223A22222C22736F75726365223A22227D01000100000024007B226D657373616765223A2248656C6C6F2066726F6D207465737420736572766572227D', 'hex');
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* 处理心跳(ping/pong)
|
|
23
|
-
*/
|
|
24
|
-
handleHeartbeat(data, socket, clientId) {
|
|
25
|
-
// 心跳数据是纯文本 "ping"(4字节),需要精确匹配
|
|
26
|
-
// 如果数据长度正好是4字节且内容是"ping",则认为是心跳
|
|
27
|
-
if (data.length === 4) {
|
|
28
|
-
const dataStr = data.toString('utf8');
|
|
29
|
-
if (dataStr === 'ping') {
|
|
30
|
-
// 记录接收到心跳
|
|
31
|
-
console.log(`💓 Received ping from ${clientId}`);
|
|
32
|
-
// 响应心跳
|
|
33
|
-
socket.write(Buffer.from('pong'), (err) => {
|
|
34
|
-
if (err) {
|
|
35
|
-
console.error(`❌ Error sending pong to ${clientId}:`, err.message);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
console.log(`💓 Sent pong to ${clientId}`);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
// 如果数据长度小于协议最小长度(22字节),且不是心跳,可能是其他非协议数据
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* 处理协议数据
|
|
49
|
-
*/
|
|
50
|
-
handleProtocolData(clientId, data) {
|
|
51
|
-
const client = this.clients.get(clientId);
|
|
52
|
-
if (!client)
|
|
53
|
-
return;
|
|
54
|
-
// 将新数据追加到接收缓冲区
|
|
55
|
-
if (!client.receiveBuffer || client.receiveBuffer.length === 0) {
|
|
56
|
-
client.receiveBuffer = data;
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
client.receiveBuffer = Buffer.concat([client.receiveBuffer, data]);
|
|
60
|
-
}
|
|
61
|
-
// 提取所有完整协议包
|
|
62
|
-
const { packets, remaining, invalidPackets } = this.protocolHandler.extractAllCompletePackets(client.receiveBuffer);
|
|
63
|
-
// 处理校验失败的废包
|
|
64
|
-
if (invalidPackets.length > 0) {
|
|
65
|
-
console.log(`⚠️ Invalid packets detected from ${clientId}: ${invalidPackets.length} packets dropped`);
|
|
66
|
-
}
|
|
67
|
-
// 处理每个有效完整包
|
|
68
|
-
for (const packet of packets) {
|
|
69
|
-
try {
|
|
70
|
-
const parseResult = this.protocolHandler.parse(packet);
|
|
71
|
-
const { data: requestData, header, requestId, isResponse } = parseResult;
|
|
72
|
-
console.log(`📨 Received protocol packet from ${clientId}:`);
|
|
73
|
-
console.log(` RequestId: ${requestId}`);
|
|
74
|
-
console.log(` IsResponse: ${isResponse}`);
|
|
75
|
-
console.log(` Header:`, JSON.stringify(header, null, 2));
|
|
76
|
-
console.log(` Data:`, JSON.stringify(requestData, null, 2));
|
|
77
|
-
console.log(` Size: ${packet.length} bytes`);
|
|
78
|
-
console.log(` Raw Hex: ${packet.toString('hex').toUpperCase().substring(0, 100)}...\n`);
|
|
79
|
-
// 如果不是响应包,则发送响应(回发相同的数据)
|
|
80
|
-
if (!isResponse) {
|
|
81
|
-
console.log(`📤 Sending response back to ${clientId}...`);
|
|
82
|
-
this.sendResponse(clientId, requestId, requestData, header);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
console.error(`❌ Error parsing packet from ${clientId}:`, error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// 更新接收缓冲区为剩余数据(半包数据保留)
|
|
90
|
-
client.receiveBuffer = remaining;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* 发送响应
|
|
94
|
-
*/
|
|
95
|
-
sendResponse(clientId, requestId, requestData, requestHeader) {
|
|
96
|
-
const client = this.clients.get(clientId);
|
|
97
|
-
if (!client || !client.socket.writable)
|
|
98
|
-
return;
|
|
99
|
-
// 构建响应数据(回发相同的数据,便于验证)
|
|
100
|
-
const responseData = requestData; // 直接回发原始数据
|
|
101
|
-
const responseHeader = requestHeader; // 使用相同的 header
|
|
102
|
-
// 构建协议响应包
|
|
103
|
-
const responsePacket = this.protocolHandler.build(responseData, responseHeader, {
|
|
104
|
-
seqId: requestId, // 使用相同的 requestId
|
|
105
|
-
isResponse: true, // 标记为响应包
|
|
106
|
-
});
|
|
107
|
-
// 发送响应
|
|
108
|
-
client.socket.write(responsePacket, (err) => {
|
|
109
|
-
if (err) {
|
|
110
|
-
console.error(`❌ Error sending response to ${clientId}:`, err.message);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
client.sentBytes += responsePacket.length;
|
|
114
|
-
console.log(`📤 Sent response to ${clientId}:`);
|
|
115
|
-
console.log(` RequestId: ${requestId}`);
|
|
116
|
-
console.log(` Response:`, responseData);
|
|
117
|
-
console.log(` Size: ${responsePacket.length} bytes\n`);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* 启动服务器
|
|
123
|
-
*/
|
|
124
|
-
start() {
|
|
125
|
-
this.server = net.createServer((socket) => {
|
|
126
|
-
const clientId = `${socket.remoteAddress}:${socket.remotePort}`;
|
|
127
|
-
console.log(`✅ Client connected: ${clientId}`);
|
|
128
|
-
// 保存客户端信息
|
|
129
|
-
this.clients.set(clientId, {
|
|
130
|
-
socket,
|
|
131
|
-
connectedAt: new Date(),
|
|
132
|
-
receivedBytes: 0,
|
|
133
|
-
sentBytes: 0,
|
|
134
|
-
receiveBuffer: null,
|
|
135
|
-
});
|
|
136
|
-
// 客户端连接后,20秒后自动发送预设的测试数据包(已注释,避免干扰测试)
|
|
137
|
-
// setTimeout(() => {
|
|
138
|
-
// console.log(`⏰ 20 seconds elapsed, sending test data packet to ${clientId}...`);
|
|
139
|
-
// this.sendTestDataPacket(clientId);
|
|
140
|
-
// }, 20000); // 延迟20秒发送
|
|
141
|
-
// 客户端连接后,自动发送预设的测试数据包(可选,通过环境变量控制)(已注释)
|
|
142
|
-
// 可以通过环境变量 AUTO_SEND_TEST_DATA 控制是否自动发送
|
|
143
|
-
// if (process.env.AUTO_SEND_TEST_DATA === 'true') {
|
|
144
|
-
// setTimeout(() => {
|
|
145
|
-
// this.sendTestDataPacket(clientId);
|
|
146
|
-
// }, 1000); // 延迟1秒发送,确保连接稳定
|
|
147
|
-
// }
|
|
148
|
-
// 接收数据
|
|
149
|
-
socket.on('data', (data) => {
|
|
150
|
-
const client = this.clients.get(clientId);
|
|
151
|
-
if (client) {
|
|
152
|
-
client.receivedBytes += data.length;
|
|
153
|
-
}
|
|
154
|
-
// 先检查是否是心跳(必须在处理协议数据之前)
|
|
155
|
-
// 心跳数据是纯文本 "ping",不应该被当作协议数据包处理
|
|
156
|
-
if (this.handleHeartbeat(data, socket, clientId)) {
|
|
157
|
-
// 心跳已处理,不继续处理(静默处理,不输出日志以避免日志过多)
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
// 注意:不要在这里过滤小段数据!
|
|
161
|
-
// 即使是小段数据(小于22字节),也应该传递给 handleProtocolData
|
|
162
|
-
// 因为协议处理器需要这些数据来组装半包
|
|
163
|
-
// handleProtocolData 内部会维护接收缓冲区,只有当缓冲区中有完整包时才会处理
|
|
164
|
-
// 处理协议数据(包括半包数据)
|
|
165
|
-
this.handleProtocolData(clientId, data);
|
|
166
|
-
});
|
|
167
|
-
// 客户端断开连接
|
|
168
|
-
socket.on('close', (_hadError) => {
|
|
169
|
-
const client = this.clients.get(clientId);
|
|
170
|
-
if (client) {
|
|
171
|
-
const duration = Date.now() - client.connectedAt.getTime();
|
|
172
|
-
console.log(`🔌 Client disconnected: ${clientId}`);
|
|
173
|
-
console.log(` Duration: ${(duration / 1000).toFixed(2)}s`);
|
|
174
|
-
console.log(` Received: ${client.receivedBytes} bytes`);
|
|
175
|
-
console.log(` Sent: ${client.sentBytes} bytes\n`);
|
|
176
|
-
}
|
|
177
|
-
this.clients.delete(clientId);
|
|
178
|
-
});
|
|
179
|
-
// 错误处理
|
|
180
|
-
socket.on('error', (err) => {
|
|
181
|
-
console.error(`❌ Socket error for ${clientId}:`, err.message);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
// 服务器错误处理
|
|
185
|
-
this.server.on('error', (err) => {
|
|
186
|
-
console.error('❌ Server error:', err.message);
|
|
187
|
-
if (err.code === 'EADDRINUSE') {
|
|
188
|
-
console.error(` Port ${this.port} is already in use.`);
|
|
189
|
-
console.error(' Please use a different port or stop the existing server.\n');
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
// 开始监听
|
|
193
|
-
this.server.listen(this.port, this.host, () => {
|
|
194
|
-
console.log('🚀 TCP Test Server started (Uniform Protocol)');
|
|
195
|
-
console.log(` Listening on ${this.host}:${this.port}`);
|
|
196
|
-
console.log(` Protocol: Uniform Protocol`);
|
|
197
|
-
console.log(` Heartbeat: ping/pong`);
|
|
198
|
-
if (process.env.AUTO_SEND_TEST_DATA === 'true') {
|
|
199
|
-
console.log(` Auto-send test data: Enabled (will send after client connects)`);
|
|
200
|
-
}
|
|
201
|
-
console.log(` Ready to accept connections...\n`);
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* 停止服务器
|
|
206
|
-
*/
|
|
207
|
-
stop() {
|
|
208
|
-
if (this.server) {
|
|
209
|
-
console.log('\n🛑 Stopping server...');
|
|
210
|
-
// 关闭所有客户端连接
|
|
211
|
-
for (const [clientId, client] of this.clients.entries()) {
|
|
212
|
-
console.log(` Closing connection: ${clientId}`);
|
|
213
|
-
client.socket.destroy();
|
|
214
|
-
}
|
|
215
|
-
this.clients.clear();
|
|
216
|
-
// 关闭服务器
|
|
217
|
-
this.server.close(() => {
|
|
218
|
-
console.log(' Server stopped\n');
|
|
219
|
-
});
|
|
220
|
-
this.server = null;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* 获取连接的客户端数量
|
|
225
|
-
*/
|
|
226
|
-
getClientCount() {
|
|
227
|
-
return this.clients.size;
|
|
228
|
-
}
|
|
229
|
-
/**
|
|
230
|
-
* 向所有客户端发送测试数据(使用 Uniform Protocol)
|
|
231
|
-
*/
|
|
232
|
-
broadcastTestData(data, header = {}) {
|
|
233
|
-
if (this.clients.size === 0) {
|
|
234
|
-
console.log('⚠️ No clients connected');
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
console.log(`📤 Broadcasting test data to ${this.clients.size} client(s)...`);
|
|
238
|
-
// 构建协议包
|
|
239
|
-
const testPacket = this.protocolHandler.build(data, header, {
|
|
240
|
-
isResponse: false,
|
|
241
|
-
});
|
|
242
|
-
for (const [clientId, client] of this.clients.entries()) {
|
|
243
|
-
client.socket.write(testPacket, (err) => {
|
|
244
|
-
if (err) {
|
|
245
|
-
console.error(`❌ Error broadcasting to ${clientId}:`, err.message);
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
client.sentBytes += testPacket.length;
|
|
249
|
-
console.log(` Sent to ${clientId}: ${JSON.stringify(data)}`);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
console.log('');
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* 断开所有客户端连接(模拟服务器断开)
|
|
257
|
-
*/
|
|
258
|
-
disconnectAllClients() {
|
|
259
|
-
console.log(`🔌 Disconnecting all ${this.clients.size} client(s)...\n`);
|
|
260
|
-
for (const client of this.clients.values()) {
|
|
261
|
-
client.socket.destroy();
|
|
262
|
-
}
|
|
263
|
-
this.clients.clear();
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* 向指定客户端发送预设的测试数据包(原始十六进制数据)
|
|
267
|
-
* @param clientId 客户端ID,如果为null则向所有客户端发送
|
|
268
|
-
*/
|
|
269
|
-
sendTestDataPacket(clientId) {
|
|
270
|
-
if (clientId) {
|
|
271
|
-
// 向指定客户端发送
|
|
272
|
-
const client = this.clients.get(clientId);
|
|
273
|
-
if (!client || !client.socket.writable) {
|
|
274
|
-
console.log(`⚠️ Client ${clientId} not found or not writable`);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
client.socket.write(this.testDataPacket, (err) => {
|
|
278
|
-
if (err) {
|
|
279
|
-
console.error(`❌ Error sending test data packet to ${clientId}:`, err.message);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
client.sentBytes += this.testDataPacket.length;
|
|
283
|
-
console.log(`📤 Sent test data packet to ${clientId}:`);
|
|
284
|
-
console.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}`);
|
|
285
|
-
console.log(` Size: ${this.testDataPacket.length} bytes\n`);
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
// 向所有客户端发送
|
|
291
|
-
if (this.clients.size === 0) {
|
|
292
|
-
console.log('⚠️ No clients connected');
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
console.log(`📤 Broadcasting test data packet to ${this.clients.size} client(s)...`);
|
|
296
|
-
for (const [id, client] of this.clients.entries()) {
|
|
297
|
-
if (client.socket.writable) {
|
|
298
|
-
client.socket.write(this.testDataPacket, (err) => {
|
|
299
|
-
if (err) {
|
|
300
|
-
console.error(`❌ Error sending test data packet to ${id}:`, err.message);
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
client.sentBytes += this.testDataPacket.length;
|
|
304
|
-
console.log(` Sent to ${id}: ${this.testDataPacket.length} bytes`);
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
console.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}\n`);
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
/**
|
|
313
|
-
* 向所有客户端发送原始十六进制数据
|
|
314
|
-
* @param hexString 十六进制字符串(空格分隔或连续)
|
|
315
|
-
*/
|
|
316
|
-
sendRawHexData(hexString, clientId) {
|
|
317
|
-
// 移除空格并转换为Buffer
|
|
318
|
-
const hex = hexString.replace(/\s+/g, '');
|
|
319
|
-
let data;
|
|
320
|
-
try {
|
|
321
|
-
data = Buffer.from(hex, 'hex');
|
|
322
|
-
}
|
|
323
|
-
catch (error) {
|
|
324
|
-
console.error(`❌ Invalid hex string: ${error}`);
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
if (clientId) {
|
|
328
|
-
// 向指定客户端发送
|
|
329
|
-
const client = this.clients.get(clientId);
|
|
330
|
-
if (!client || !client.socket.writable) {
|
|
331
|
-
console.log(`⚠️ Client ${clientId} not found or not writable`);
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
client.socket.write(data, (err) => {
|
|
335
|
-
if (err) {
|
|
336
|
-
console.error(`❌ Error sending raw hex data to ${clientId}:`, err.message);
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
client.sentBytes += data.length;
|
|
340
|
-
console.log(`📤 Sent raw hex data to ${clientId}:`);
|
|
341
|
-
console.log(` Hex: ${data.toString('hex').toUpperCase()}`);
|
|
342
|
-
console.log(` Size: ${data.length} bytes\n`);
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
else {
|
|
347
|
-
// 向所有客户端发送
|
|
348
|
-
if (this.clients.size === 0) {
|
|
349
|
-
console.log('⚠️ No clients connected');
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
console.log(`📤 Broadcasting raw hex data to ${this.clients.size} client(s)...`);
|
|
353
|
-
for (const [id, client] of this.clients.entries()) {
|
|
354
|
-
if (client.socket.writable) {
|
|
355
|
-
client.socket.write(data, (err) => {
|
|
356
|
-
if (err) {
|
|
357
|
-
console.error(`❌ Error sending raw hex data to ${id}:`, err.message);
|
|
358
|
-
}
|
|
359
|
-
else {
|
|
360
|
-
client.sentBytes += data.length;
|
|
361
|
-
console.log(` Sent to ${id}: ${data.length} bytes`);
|
|
362
|
-
}
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
console.log(` Hex: ${data.toString('hex').toUpperCase()}\n`);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
// 主函数
|
|
371
|
-
function main() {
|
|
372
|
-
const port = parseInt(process.env.PORT || '8080', 10);
|
|
373
|
-
const host = process.env.HOST || '127.0.0.1';
|
|
374
|
-
const server = new TestTCPServer(port, host);
|
|
375
|
-
// 启动服务器
|
|
376
|
-
server.start();
|
|
377
|
-
// 处理 Ctrl+C 优雅退出
|
|
378
|
-
const exitHandler = () => {
|
|
379
|
-
console.log('\n');
|
|
380
|
-
server.stop();
|
|
381
|
-
process.exit(0);
|
|
382
|
-
};
|
|
383
|
-
process.on('SIGINT', exitHandler);
|
|
384
|
-
process.on('SIGTERM', exitHandler);
|
|
385
|
-
// 可选:定期发送预设的测试数据包(取消注释以启用)
|
|
386
|
-
// const testDataInterval = setInterval(() => {
|
|
387
|
-
// if (server.getClientCount() > 0) {
|
|
388
|
-
// server.sendTestDataPacket(); // 发送预设的测试数据包
|
|
389
|
-
// }
|
|
390
|
-
// }, 10000); // 每10秒发送一次
|
|
391
|
-
// 可选:定期发送协议格式的测试数据(取消注释以启用)
|
|
392
|
-
// const protocolTestInterval = setInterval(() => {
|
|
393
|
-
// if (server.getClientCount() > 0) {
|
|
394
|
-
// server.broadcastTestData(
|
|
395
|
-
// { message: 'Broadcast test', timestamp: Date.now() },
|
|
396
|
-
// { type: 'broadcast', version: '1.0' }
|
|
397
|
-
// );
|
|
398
|
-
// }
|
|
399
|
-
// }, 10000); // 每10秒发送一次
|
|
400
|
-
// 清理定时器(如果使用了)
|
|
401
|
-
// process.on('exit', () => {
|
|
402
|
-
// clearInterval(testDataInterval);
|
|
403
|
-
// clearInterval(protocolTestInterval);
|
|
404
|
-
// });
|
|
405
|
-
}
|
|
406
|
-
// 如果直接运行此文件,启动服务器
|
|
407
|
-
if (import.meta.url === `file://${process.argv[1]?.replace(/\\/g, '/')}` ||
|
|
408
|
-
process.argv[1]?.includes('test-server.ts')) {
|
|
409
|
-
main();
|
|
410
|
-
}
|
|
411
|
-
export { TestTCPServer };
|
|
412
|
-
//# sourceMappingURL=test-server.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"test-server.js","sourceRoot":"","sources":["../../../src/packages/tcp/test-server.ts"],"names":[],"mappings":"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","sourcesContent":["// ALL_CODE_LINE: 462\r\n// AI_CODE_LINE: 462\r\n\r\nimport * as net from 'net';\r\nimport { ProtocolHandler } from './protocolHandler.js';\r\n\r\n/**\r\n * 支持 Uniform Protocol 的 TCP 测试服务器\r\n * 用于测试 SocketWrapper 的功能\r\n *\r\n * 功能:\r\n * - 接收客户端连接\r\n * - 处理 Uniform Protocol 格式的数据包\r\n * - 解析请求并发送响应(使用 Uniform Protocol 格式)\r\n * - 处理心跳(ping/pong)\r\n * - 可以主动发送测试数据\r\n * - 支持模拟断开连接\r\n *\r\n * 使用方式:\r\n * npm run test-server\r\n * 或\r\n * npx tsx src/packages/tcp/test-server.ts\r\n */\r\n\r\ninterface ClientInfo {\r\n\tsocket: net.Socket;\r\n\tconnectedAt: Date;\r\n\treceivedBytes: number;\r\n\tsentBytes: number;\r\n\treceiveBuffer: Buffer | null;\r\n}\r\n\r\nclass TestTCPServer {\r\n\tprivate server: net.Server | null = null;\r\n\tprivate clients: Map<string, ClientInfo> = new Map();\r\n\tprivate port: number;\r\n\tprivate host: string;\r\n\tprivate protocolHandler: ProtocolHandler;\r\n\t/** 预设的测试数据包(十六进制) */\r\n\tprivate readonly testDataPacket: Buffer;\r\n\r\n\tconstructor(port: number = 8080, host: string = '127.0.0.1') {\r\n\t\tthis.port = port;\r\n\t\tthis.host = host;\r\n\t\tthis.protocolHandler = new ProtocolHandler();\r\n\t\t// 标准测试数据包(使用 ProtocolHandler.build 生成)\r\n\t\t// 包含完整的 Frame Head、Request Head 和 TLV 数据,符合协议规范\r\n\t\tthis.testDataPacket = Buffer.from(\r\n\t\t\t'4E4F56410101000000000000000000005B0079796B20010000000100000000001030500000001D007B22736571223A302C22736E223A22222C22736F75726365223A22227D01000100000024007B226D657373616765223A2248656C6C6F2066726F6D207465737420736572766572227D',\r\n\t\t\t'hex'\r\n\t\t);\r\n\t}\r\n\r\n\t/**\r\n\t * 处理心跳(ping/pong)\r\n\t */\r\n\tprivate handleHeartbeat(data: Buffer, socket: net.Socket, clientId: string): boolean {\r\n\t\t// 心跳数据是纯文本 \"ping\"(4字节),需要精确匹配\r\n\t\t// 如果数据长度正好是4字节且内容是\"ping\",则认为是心跳\r\n\t\tif (data.length === 4) {\r\n\t\t\tconst dataStr = data.toString('utf8');\r\n\t\t\tif (dataStr === 'ping') {\r\n\t\t\t\t// 记录接收到心跳\r\n\t\t\t\tconsole.log(`💓 Received ping from ${clientId}`);\r\n\t\t\t\t// 响应心跳\r\n\t\t\t\tsocket.write(Buffer.from('pong'), (err) => {\r\n\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\tconsole.error(`❌ Error sending pong to ${clientId}:`, err.message);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tconsole.log(`💓 Sent pong to ${clientId}`);\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t// 如果数据长度小于协议最小长度(22字节),且不是心跳,可能是其他非协议数据\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t * 处理协议数据\r\n\t */\r\n\tprivate handleProtocolData(clientId: string, data: Buffer): void {\r\n\t\tconst client = this.clients.get(clientId);\r\n\t\tif (!client) return;\r\n\r\n\t\t// 将新数据追加到接收缓冲区\r\n\t\tif (!client.receiveBuffer || client.receiveBuffer.length === 0) {\r\n\t\t\tclient.receiveBuffer = data;\r\n\t\t} else {\r\n\t\t\tclient.receiveBuffer = Buffer.concat([client.receiveBuffer, data]);\r\n\t\t}\r\n\r\n\t\t// 提取所有完整协议包\r\n\t\tconst { packets, remaining, invalidPackets } = this.protocolHandler.extractAllCompletePackets(client.receiveBuffer);\r\n\r\n\t\t// 处理校验失败的废包\r\n\t\tif (invalidPackets.length > 0) {\r\n\t\t\tconsole.log(`⚠️ Invalid packets detected from ${clientId}: ${invalidPackets.length} packets dropped`);\r\n\t\t}\r\n\r\n\t\t// 处理每个有效完整包\r\n\t\tfor (const packet of packets) {\r\n\t\t\ttry {\r\n\t\t\t\tconst parseResult = this.protocolHandler.parse(packet);\r\n\t\t\t\tconst { data: requestData, header, requestId, isResponse } = parseResult;\r\n\r\n\t\t\t\tconsole.log(`📨 Received protocol packet from ${clientId}:`);\r\n\t\t\t\tconsole.log(` RequestId: ${requestId}`);\r\n\t\t\t\tconsole.log(` IsResponse: ${isResponse}`);\r\n\t\t\t\tconsole.log(` Header:`, JSON.stringify(header, null, 2));\r\n\t\t\t\tconsole.log(` Data:`, JSON.stringify(requestData, null, 2));\r\n\t\t\t\tconsole.log(` Size: ${packet.length} bytes`);\r\n\t\t\t\tconsole.log(` Raw Hex: ${packet.toString('hex').toUpperCase().substring(0, 100)}...\\n`);\r\n\r\n\t\t\t\t// 如果不是响应包,则发送响应(回发相同的数据)\r\n\t\t\t\tif (!isResponse) {\r\n\t\t\t\t\tconsole.log(`📤 Sending response back to ${clientId}...`);\r\n\t\t\t\t\tthis.sendResponse(clientId, requestId, requestData, header);\r\n\t\t\t\t}\r\n\t\t\t} catch (error) {\r\n\t\t\t\tconsole.error(`❌ Error parsing packet from ${clientId}:`, error);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 更新接收缓冲区为剩余数据(半包数据保留)\r\n\t\tclient.receiveBuffer = remaining;\r\n\t}\r\n\r\n\t/**\r\n\t * 发送响应\r\n\t */\r\n\tprivate sendResponse(clientId: string, requestId: number, requestData: any, requestHeader: any): void {\r\n\t\tconst client = this.clients.get(clientId);\r\n\t\tif (!client || !client.socket.writable) return;\r\n\r\n\t\t// 构建响应数据(回发相同的数据,便于验证)\r\n\t\tconst responseData = requestData; // 直接回发原始数据\r\n\r\n\t\tconst responseHeader = requestHeader; // 使用相同的 header\r\n\r\n\t\t// 构建协议响应包\r\n\t\tconst responsePacket = this.protocolHandler.build(responseData, responseHeader, {\r\n\t\t\tseqId: requestId, // 使用相同的 requestId\r\n\t\t\tisResponse: true, // 标记为响应包\r\n\t\t});\r\n\r\n\t\t// 发送响应\r\n\t\tclient.socket.write(responsePacket, (err) => {\r\n\t\t\tif (err) {\r\n\t\t\t\tconsole.error(`❌ Error sending response to ${clientId}:`, err.message);\r\n\t\t\t} else {\r\n\t\t\t\tclient.sentBytes += responsePacket.length;\r\n\t\t\t\tconsole.log(`📤 Sent response to ${clientId}:`);\r\n\t\t\t\tconsole.log(` RequestId: ${requestId}`);\r\n\t\t\t\tconsole.log(` Response:`, responseData);\r\n\t\t\t\tconsole.log(` Size: ${responsePacket.length} bytes\\n`);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * 启动服务器\r\n\t */\r\n\tstart(): void {\r\n\t\tthis.server = net.createServer((socket) => {\r\n\t\t\tconst clientId = `${socket.remoteAddress}:${socket.remotePort}`;\r\n\t\t\tconsole.log(`✅ Client connected: ${clientId}`);\r\n\r\n\t\t\t// 保存客户端信息\r\n\t\t\tthis.clients.set(clientId, {\r\n\t\t\t\tsocket,\r\n\t\t\t\tconnectedAt: new Date(),\r\n\t\t\t\treceivedBytes: 0,\r\n\t\t\t\tsentBytes: 0,\r\n\t\t\t\treceiveBuffer: null,\r\n\t\t\t});\r\n\r\n\t\t\t// 客户端连接后,20秒后自动发送预设的测试数据包(已注释,避免干扰测试)\r\n\t\t\t// setTimeout(() => {\r\n\t\t\t// \tconsole.log(`⏰ 20 seconds elapsed, sending test data packet to ${clientId}...`);\r\n\t\t\t// \tthis.sendTestDataPacket(clientId);\r\n\t\t\t// }, 20000); // 延迟20秒发送\r\n\r\n\t\t\t// 客户端连接后,自动发送预设的测试数据包(可选,通过环境变量控制)(已注释)\r\n\t\t\t// 可以通过环境变量 AUTO_SEND_TEST_DATA 控制是否自动发送\r\n\t\t\t// if (process.env.AUTO_SEND_TEST_DATA === 'true') {\r\n\t\t\t// \tsetTimeout(() => {\r\n\t\t\t// \t\tthis.sendTestDataPacket(clientId);\r\n\t\t\t// \t}, 1000); // 延迟1秒发送,确保连接稳定\r\n\t\t\t// }\r\n\r\n\t\t\t// 接收数据\r\n\t\t\tsocket.on('data', (data: Buffer) => {\r\n\t\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\t\tif (client) {\r\n\t\t\t\t\tclient.receivedBytes += data.length;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 先检查是否是心跳(必须在处理协议数据之前)\r\n\t\t\t\t// 心跳数据是纯文本 \"ping\",不应该被当作协议数据包处理\r\n\t\t\t\tif (this.handleHeartbeat(data, socket, clientId)) {\r\n\t\t\t\t\t// 心跳已处理,不继续处理(静默处理,不输出日志以避免日志过多)\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 注意:不要在这里过滤小段数据!\r\n\t\t\t\t// 即使是小段数据(小于22字节),也应该传递给 handleProtocolData\r\n\t\t\t\t// 因为协议处理器需要这些数据来组装半包\r\n\t\t\t\t// handleProtocolData 内部会维护接收缓冲区,只有当缓冲区中有完整包时才会处理\r\n\r\n\t\t\t\t// 处理协议数据(包括半包数据)\r\n\t\t\t\tthis.handleProtocolData(clientId, data);\r\n\t\t\t});\r\n\r\n\t\t\t// 客户端断开连接\r\n\t\t\tsocket.on('close', (_hadError) => {\r\n\t\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\t\tif (client) {\r\n\t\t\t\t\tconst duration = Date.now() - client.connectedAt.getTime();\r\n\t\t\t\t\tconsole.log(`🔌 Client disconnected: ${clientId}`);\r\n\t\t\t\t\tconsole.log(` Duration: ${(duration / 1000).toFixed(2)}s`);\r\n\t\t\t\t\tconsole.log(` Received: ${client.receivedBytes} bytes`);\r\n\t\t\t\t\tconsole.log(` Sent: ${client.sentBytes} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t\tthis.clients.delete(clientId);\r\n\t\t\t});\r\n\r\n\t\t\t// 错误处理\r\n\t\t\tsocket.on('error', (err) => {\r\n\t\t\t\tconsole.error(`❌ Socket error for ${clientId}:`, err.message);\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t\t// 服务器错误处理\r\n\t\tthis.server.on('error', (err) => {\r\n\t\t\tconsole.error('❌ Server error:', err.message);\r\n\t\t\tif ((err as NodeJS.ErrnoException).code === 'EADDRINUSE') {\r\n\t\t\t\tconsole.error(` Port ${this.port} is already in use.`);\r\n\t\t\t\tconsole.error(' Please use a different port or stop the existing server.\\n');\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 开始监听\r\n\t\tthis.server.listen(this.port, this.host, () => {\r\n\t\t\tconsole.log('🚀 TCP Test Server started (Uniform Protocol)');\r\n\t\t\tconsole.log(` Listening on ${this.host}:${this.port}`);\r\n\t\t\tconsole.log(` Protocol: Uniform Protocol`);\r\n\t\t\tconsole.log(` Heartbeat: ping/pong`);\r\n\t\t\tif (process.env.AUTO_SEND_TEST_DATA === 'true') {\r\n\t\t\t\tconsole.log(` Auto-send test data: Enabled (will send after client connects)`);\r\n\t\t\t}\r\n\t\t\tconsole.log(` Ready to accept connections...\\n`);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * 停止服务器\r\n\t */\r\n\tstop(): void {\r\n\t\tif (this.server) {\r\n\t\t\tconsole.log('\\n🛑 Stopping server...');\r\n\r\n\t\t\t// 关闭所有客户端连接\r\n\t\t\tfor (const [clientId, client] of this.clients.entries()) {\r\n\t\t\t\tconsole.log(` Closing connection: ${clientId}`);\r\n\t\t\t\tclient.socket.destroy();\r\n\t\t\t}\r\n\t\t\tthis.clients.clear();\r\n\r\n\t\t\t// 关闭服务器\r\n\t\t\tthis.server.close(() => {\r\n\t\t\t\tconsole.log(' Server stopped\\n');\r\n\t\t\t});\r\n\t\t\tthis.server = null;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 获取连接的客户端数量\r\n\t */\r\n\tgetClientCount(): number {\r\n\t\treturn this.clients.size;\r\n\t}\r\n\r\n\t/**\r\n\t * 向所有客户端发送测试数据(使用 Uniform Protocol)\r\n\t */\r\n\tbroadcastTestData(data: any, header: any = {}): void {\r\n\t\tif (this.clients.size === 0) {\r\n\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconsole.log(`📤 Broadcasting test data to ${this.clients.size} client(s)...`);\r\n\r\n\t\t// 构建协议包\r\n\t\tconst testPacket = this.protocolHandler.build(data, header, {\r\n\t\t\tisResponse: false,\r\n\t\t});\r\n\r\n\t\tfor (const [clientId, client] of this.clients.entries()) {\r\n\t\t\tclient.socket.write(testPacket, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error broadcasting to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += testPacket.length;\r\n\t\t\t\t\tconsole.log(` Sent to ${clientId}: ${JSON.stringify(data)}`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n\r\n\t/**\r\n\t * 断开所有客户端连接(模拟服务器断开)\r\n\t */\r\n\tdisconnectAllClients(): void {\r\n\t\tconsole.log(`🔌 Disconnecting all ${this.clients.size} client(s)...\\n`);\r\n\t\tfor (const client of this.clients.values()) {\r\n\t\t\tclient.socket.destroy();\r\n\t\t}\r\n\t\tthis.clients.clear();\r\n\t}\r\n\r\n\t/**\r\n\t * 向指定客户端发送预设的测试数据包(原始十六进制数据)\r\n\t * @param clientId 客户端ID,如果为null则向所有客户端发送\r\n\t */\r\n\tsendTestDataPacket(clientId?: string | null): void {\r\n\t\tif (clientId) {\r\n\t\t\t// 向指定客户端发送\r\n\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\tif (!client || !client.socket.writable) {\r\n\t\t\t\tconsole.log(`⚠️ Client ${clientId} not found or not writable`);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tclient.socket.write(this.testDataPacket, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error sending test data packet to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += this.testDataPacket.length;\r\n\t\t\t\t\tconsole.log(`📤 Sent test data packet to ${clientId}:`);\r\n\t\t\t\t\tconsole.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}`);\r\n\t\t\t\t\tconsole.log(` Size: ${this.testDataPacket.length} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// 向所有客户端发送\r\n\t\t\tif (this.clients.size === 0) {\r\n\t\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconsole.log(`📤 Broadcasting test data packet to ${this.clients.size} client(s)...`);\r\n\t\t\tfor (const [id, client] of this.clients.entries()) {\r\n\t\t\t\tif (client.socket.writable) {\r\n\t\t\t\t\tclient.socket.write(this.testDataPacket, (err) => {\r\n\t\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\t\tconsole.error(`❌ Error sending test data packet to ${id}:`, err.message);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tclient.sentBytes += this.testDataPacket.length;\r\n\t\t\t\t\t\t\tconsole.log(` Sent to ${id}: ${this.testDataPacket.length} bytes`);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconsole.log(` Hex: ${this.testDataPacket.toString('hex').toUpperCase()}\\n`);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * 向所有客户端发送原始十六进制数据\r\n\t * @param hexString 十六进制字符串(空格分隔或连续)\r\n\t */\r\n\tsendRawHexData(hexString: string, clientId?: string | null): void {\r\n\t\t// 移除空格并转换为Buffer\r\n\t\tconst hex = hexString.replace(/\\s+/g, '');\r\n\t\tlet data: Buffer;\r\n\t\ttry {\r\n\t\t\tdata = Buffer.from(hex, 'hex');\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error(`❌ Invalid hex string: ${error}`);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (clientId) {\r\n\t\t\t// 向指定客户端发送\r\n\t\t\tconst client = this.clients.get(clientId);\r\n\t\t\tif (!client || !client.socket.writable) {\r\n\t\t\t\tconsole.log(`⚠️ Client ${clientId} not found or not writable`);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tclient.socket.write(data, (err) => {\r\n\t\t\t\tif (err) {\r\n\t\t\t\t\tconsole.error(`❌ Error sending raw hex data to ${clientId}:`, err.message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tclient.sentBytes += data.length;\r\n\t\t\t\t\tconsole.log(`📤 Sent raw hex data to ${clientId}:`);\r\n\t\t\t\t\tconsole.log(` Hex: ${data.toString('hex').toUpperCase()}`);\r\n\t\t\t\t\tconsole.log(` Size: ${data.length} bytes\\n`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// 向所有客户端发送\r\n\t\t\tif (this.clients.size === 0) {\r\n\t\t\t\tconsole.log('⚠️ No clients connected');\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tconsole.log(`📤 Broadcasting raw hex data to ${this.clients.size} client(s)...`);\r\n\t\t\tfor (const [id, client] of this.clients.entries()) {\r\n\t\t\t\tif (client.socket.writable) {\r\n\t\t\t\t\tclient.socket.write(data, (err) => {\r\n\t\t\t\t\t\tif (err) {\r\n\t\t\t\t\t\t\tconsole.error(`❌ Error sending raw hex data to ${id}:`, err.message);\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\tclient.sentBytes += data.length;\r\n\t\t\t\t\t\t\tconsole.log(` Sent to ${id}: ${data.length} bytes`);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconsole.log(` Hex: ${data.toString('hex').toUpperCase()}\\n`);\r\n\t\t}\r\n\t}\r\n}\r\n\r\n// 主函数\r\nfunction main() {\r\n\tconst port = parseInt(process.env.PORT || '8080', 10);\r\n\tconst host = process.env.HOST || '127.0.0.1';\r\n\r\n\tconst server = new TestTCPServer(port, host);\r\n\r\n\t// 启动服务器\r\n\tserver.start();\r\n\r\n\t// 处理 Ctrl+C 优雅退出\r\n\tconst exitHandler = () => {\r\n\t\tconsole.log('\\n');\r\n\t\tserver.stop();\r\n\t\tprocess.exit(0);\r\n\t};\r\n\r\n\tprocess.on('SIGINT', exitHandler);\r\n\tprocess.on('SIGTERM', exitHandler);\r\n\r\n\t// 可选:定期发送预设的测试数据包(取消注释以启用)\r\n\t// const testDataInterval = setInterval(() => {\r\n\t// \tif (server.getClientCount() > 0) {\r\n\t// \t\tserver.sendTestDataPacket(); // 发送预设的测试数据包\r\n\t// \t}\r\n\t// }, 10000); // 每10秒发送一次\r\n\r\n\t// 可选:定期发送协议格式的测试数据(取消注释以启用)\r\n\t// const protocolTestInterval = setInterval(() => {\r\n\t// \tif (server.getClientCount() > 0) {\r\n\t// \t\tserver.broadcastTestData(\r\n\t// \t\t\t{ message: 'Broadcast test', timestamp: Date.now() },\r\n\t// \t\t\t{ type: 'broadcast', version: '1.0' }\r\n\t// \t\t);\r\n\t// \t}\r\n\t// }, 10000); // 每10秒发送一次\r\n\r\n\t// 清理定时器(如果使用了)\r\n\t// process.on('exit', () => {\r\n\t// \tclearInterval(testDataInterval);\r\n\t// \tclearInterval(protocolTestInterval);\r\n\t// });\r\n}\r\n\r\n// 如果直接运行此文件,启动服务器\r\nif (\r\n\timport.meta.url === `file://${process.argv[1]?.replace(/\\\\/g, '/')}` ||\r\n\tprocess.argv[1]?.includes('test-server.ts')\r\n) {\r\n\tmain();\r\n}\r\n\r\nexport { TestTCPServer };\r\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/packages/tcp/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/packages/tcp/types.ts"],"names":[],"mappings":"AA2CA;;GAEG;AACH,MAAM,CAAN,IAAY,qBAOX;AAPD,WAAY,qBAAqB;IAChC,cAAc;IACd,oDAA2B,CAAA;IAC3B,cAAc;IACd,oDAA2B,CAAA;IAC3B,iBAAiB;IACjB,0CAAiB,CAAA;AAClB,CAAC,EAPW,qBAAqB,KAArB,qBAAqB,QAOhC","sourcesContent":["// ALL_CODE_LINE: 243\r\n// AI_CODE_LINE: 44\r\nimport { EventEmitter } from 'events';\r\nimport type { SocketWrapper } from './SocketWrapper.js';\r\n\r\n/**\r\n * 连接选项\r\n */\r\nexport interface SocketConnectOptions {\r\n\t/** 服务器主机地址 */\r\n\thost?: string;\r\n\t/** 服务器端口号 */\r\n\tport?: number;\r\n\t/** 是否启用自动重连,默认 false */\r\n\tautoReconnect?: boolean;\r\n\t/** 重连间隔(毫秒),默认 5000 */\r\n\treconnectInterval?: number;\r\n\t/** 是否启用心跳,默认 true */\r\n\tenableHeartbeat?: boolean;\r\n\t/** 心跳间隔(毫秒),默认 5000(5秒) */\r\n\theartbeatInterval?: number;\r\n\t/** 心跳超时时间(毫秒),默认 5000(5秒),如果心跳发送后超过此时间未收到响应则关闭连接 */\r\n\theartbeatTimeout?: number;\r\n\t/** 最大重连次数,默认 0 表示无限制 */\r\n\tmaxReconnectAttempts?: number;\r\n\t/** 是否启用指数退避(重连间隔逐渐增加),默认 false */\r\n\tenableExponentialBackoff?: boolean;\r\n\t/** 指数退避的最大间隔(毫秒),默认 60000(60秒) */\r\n\tmaxReconnectInterval?: number;\r\n}\r\n\r\n/**\r\n * 队列配置选项\r\n */\r\nexport interface QueueOptions {\r\n\t/** 最大队列长度,默认 1000 */\r\n\tmaxLength?: number;\r\n\t/** 溢出策略 */\r\n\toverflowStrategy?: 'drop-oldest' | 'drop-newest' | 'reject';\r\n\t/** 单条数据处理超时时间(毫秒),默认 5000 */\r\n\tprocessTimeout?: number;\r\n}\r\n\r\n/**\r\n * 队列溢出策略\r\n */\r\nexport enum QueueOverflowStrategy {\r\n\t/** 丢弃最旧的数据 */\r\n\tDROP_OLDEST = 'drop-oldest',\r\n\t/** 丢弃最新的数据 */\r\n\tDROP_NEWEST = 'drop-newest',\r\n\t/** 拒绝新数据并触发错误 */\r\n\tREJECT = 'reject',\r\n}\r\n\r\n/**\r\n * 队列监控指标\r\n */\r\nexport interface QueueMetrics {\r\n\t/** 总处理数量 */\r\n\ttotalProcessed: number;\r\n\t/** 总错误数量 */\r\n\ttotalErrors: number;\r\n\t/** 总丢弃数量 */\r\n\ttotalDropped: number;\r\n\t/** 当前队列长度 */\r\n\tcurrentLength: number;\r\n\t/** 最大队列长度 */\r\n\tmaxLength: number;\r\n\t/** 平均处理时间(毫秒) */\r\n\taverageProcessTime: number;\r\n\t/** 峰值长度 */\r\n\tpeakLength: number;\r\n\t/** 最后处理时间戳 */\r\n\tlastProcessTime: number;\r\n}\r\n\r\n/**\r\n * 协议处理选项\r\n */\r\nexport interface ProtocolHandlerOptions {\r\n\t/** 是否启用协议解析(接收时自动解析) */\r\n\tenableParsing?: boolean;\r\n\t/** 是否启用协议构建(发送时自动构建) */\r\n\tenableBuilding?: boolean;\r\n\t/** 解析选项 */\r\n\tparseOptions?: any;\r\n\t/** 默认构建选项 */\r\n\tdefaultBuildOptions?: any;\r\n}\r\n\r\n/**\r\n * 协议构建发送负载,用于统一的 send 接口\r\n */\r\nexport interface ProtocolSendPayload {\r\n\t/** 协议业务数据(TLV2 部分或等效结构) */\r\n\tdata: any;\r\n\t/** 协议头数据(TLV1 部分,可选) */\r\n\theader?: any;\r\n\t/** 协议构建选项(会与默认构建选项合并) */\r\n\toptions?: any;\r\n\t/** 是否作为响应包发送(部分协议需要显式设置) */\r\n\tisResponse?: boolean;\r\n}\r\n\r\n/**\r\n * 事件类型定义\r\n */\r\nexport interface SocketWrapperEvents {\r\n\t/** 连接成功时触发 */\r\n\tconnected: () => void;\r\n\t/** 连接断开时触发(自动重连时会触发) */\r\n\tdisconnected: () => void;\r\n\t/** 接收到数据时触发(原始数据) */\r\n\tdata: (data: Buffer, requestId: number) => void;\r\n\t/** 接收到协议数据时触发(已解析) */\r\n\tprotocolData: (result: any, requestId: number) => void;\r\n\t/** 发生错误时触发 */\r\n\terror: (error: Error, requestId?: number) => void;\r\n\t/** 连接关闭时触发 */\r\n\tclose: () => void;\r\n}\r\n\r\n/**\r\n * SocketWrapper 接口\r\n * 注意:on/emit/off/once 方法由 EventEmitter 继承提供,无需在接口中声明\r\n */\r\nexport interface ISocketWrapper {\r\n\t/**\r\n\t * 连接到服务器\r\n\t * @param host - 服务器主机地址\r\n\t * @param port - 服务器端口号\r\n\t * @param options - 连接选项\r\n\t */\r\n\tconnect(host: string, port: number, options: SocketConnectOptions): void;\r\n\t/**\r\n\t * 断开连接\r\n\t */\r\n\tdisconnect(): void;\r\n\r\n\t/**\r\n\t * 发送数据或协议包\r\n\t * @param payload - 原始 Buffer 或协议负载对象\r\n\t * @param requestId - 当发送原始 Buffer 时必须提供请求 ID\r\n\t * @returns 实际发送所使用的请求 ID\r\n\t */\r\n\tsend(payload: Buffer | ProtocolSendPayload): void;\r\n\r\n\t/**\r\n\t * 检查是否已连接\r\n\t * @returns 如果已连接返回 true,否则返回 false\r\n\t */\r\n\tisConnected(): boolean;\r\n\r\n\t/**\r\n\t * 主动触发 error 事件\r\n\t * 用于外部主动报告错误,例如业务逻辑错误、数据验证错误等\r\n\t * @param error 错误对象\r\n\t * @param requestId 可选的请求ID,用于关联特定的请求\r\n\t */\r\n\temitError(error: Error, requestId?: number): void;\r\n}\r\n\r\n/**\r\n * 内部响应队列项类型\r\n */\r\nexport interface ResponseQueueItem {\r\n\t/** 请求 ID */\r\n\trequestId: number;\r\n\t/** 响应数据 */\r\n\tdata: Buffer;\r\n}\r\n\r\n/**\r\n * SocketWrapper 实例类型\r\n */\r\nexport type SocketWrapperInstance = ISocketWrapper & EventEmitter;\r\n\r\n/**\r\n * requestId 提取函数类型\r\n * 用于从接收到的数据中提取 requestId\r\n * @param data - 接收到的数据缓冲区\r\n * @returns 提取的 requestId (seqId)\r\n */\r\nexport type RequestIdExtractor = (data: Buffer) => number;\r\n\r\n/**\r\n * 心跳包构建函数类型\r\n * @returns 心跳包数据\r\n */\r\nexport type HeartbeatBuilder = () => Buffer;\r\n\r\n/**\r\n * 心跳响应识别函数类型\r\n * @param data 接收到的数据\r\n * @returns 是否为心跳响应\r\n */\r\nexport type HeartbeatResponseChecker = (data: Buffer) => boolean;\r\n\r\n/**\r\n * 连接管理器事件类型\r\n */\r\nexport interface ConnectionManagerEvents {\r\n\t/** 连接成功时触发 */\r\n\tconnected: (socketWrapper: SocketWrapper) => void;\r\n\t/** 连接断开时触发 */\r\n\tdisconnected: (socketWrapper: SocketWrapper) => void;\r\n\t/** 发生错误时触发 */\r\n\terror: (error: string, socketWrapper?: SocketWrapper) => void;\r\n}\r\n\r\n/**\r\n * 设备发现事件\r\n */\r\nexport interface DiscoveryEvents {\r\n\t// 兼容 tcp 包的事件命名\r\n\tup: [device: MiniDiscoveredDevice];\r\n\tdown: [device: MiniDiscoveredDevice];\r\n}\r\n\r\n/**\r\n * 设备信息接口\r\n */\r\nexport interface MiniDeviceInfo {\r\n\tserialNumber: string; // 设备序列号,唯一标识设备\r\n\tversion: string; // 固件版本号\r\n\tmodel?: string; // 设备型号代码\r\n\tmodelName?: string; // 设备型号名称\r\n\tkeyLayout: { rows: number; columns: number }; // 按键布局(行数和列数)\r\n}\r\n\r\n/**\r\n * 发现的设备信息\r\n */\r\nexport interface MiniDiscoveredDevice extends MiniDeviceInfo {\r\n\taddress: string;\r\n\tport: number;\r\n\tname: string;\r\n\tlastSeen: Date;\r\n}\r\n\r\n/**\r\n * 设备发现服务选项\r\n */\r\nexport interface DiscoveryServiceOptions {\r\n\t/** 查询间隔(毫秒) */\r\n\tqueryInterval?: number;\r\n\t/** 服务类型 */\r\n\ttype?: string;\r\n\t/** 服务协议 */\r\n\tprotocol?: string;\r\n}\r\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/packages/tcp/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAepD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBpD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/packages/tcp/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACpC,IAAI,CAAC;QACJ,YAAY;QACZ,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,MAAM,CAAC,QAAQ,CAAC;QACxB,CAAC;QACD,qBAAqB;QACrB,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACpC,IAAI,CAAC;QACJ,YAAY;QACZ,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC;QAC1C,CAAC;QACD,qBAAqB;QACrB,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAClC,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC","sourcesContent":["/**\r\n * 工具函数\r\n */\r\n\r\n/**\r\n * 从 URL 解析主机地址\r\n * @param url 连接地址\r\n */\r\nexport function parseHost(url: string): string | null {\r\n\ttry {\r\n\t\t// 尝试解析为 URL\r\n\t\tif (url.includes('://')) {\r\n\t\t\tconst urlObj = new URL(url);\r\n\t\t\treturn urlObj.hostname;\r\n\t\t}\r\n\t\t// 尝试解析为 host:port 格式\r\n\t\tif (url.includes(':')) {\r\n\t\t\treturn url.split(':')[0];\r\n\t\t}\r\n\t\treturn url;\r\n\t} catch {\r\n\t\treturn null;\r\n\t}\r\n}\r\n\r\n/**\r\n * 从 URL 解析端口\r\n * @param url 连接地址\r\n */\r\nexport function parsePort(url: string): number | null {\r\n\ttry {\r\n\t\t// 尝试解析为 URL\r\n\t\tif (url.includes('://')) {\r\n\t\t\tconst urlObj = new URL(url);\r\n\t\t\treturn parseInt(urlObj.port, 10) || null;\r\n\t\t}\r\n\t\t// 尝试解析为 host:port 格式\r\n\t\tif (url.includes(':')) {\r\n\t\t\tconst port = parseInt(url.split(':')[1], 10);\r\n\t\t\treturn isNaN(port) ? null : port;\r\n\t\t}\r\n\t\treturn null;\r\n\t} catch {\r\n\t\treturn null;\r\n\t}\r\n}\r\n"]}
|