nng-ruby 0.1.1 → 0.1.2

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.
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # NNG + Protocol Buffers 高级示例
5
+ # 使用 .proto 文件和复杂的消息嵌套
6
+
7
+ require 'nng'
8
+ require 'google/protobuf'
9
+
10
+ puts "=" * 70
11
+ puts "NNG + Protocol Buffers 高级示例"
12
+ puts "使用 .proto 文件和消息嵌套"
13
+ puts "=" * 70
14
+ puts
15
+
16
+ # ============================================================================
17
+ # 1. 从 .proto 文件生成 Ruby 代码 (编译时)
18
+ # ============================================================================
19
+
20
+ puts "说明: 使用 .proto 文件"
21
+ puts "-" * 70
22
+ puts
23
+ puts "实际项目中应该使用 protoc 编译 .proto 文件:"
24
+ puts " $ protoc --ruby_out=. proto/message.proto"
25
+ puts
26
+ puts "本示例直接在 Ruby 中定义消息 (等效于编译后的代码)"
27
+ puts
28
+
29
+ # 定义消息 (等效于从 message.proto 编译生成)
30
+ Google::Protobuf::DescriptorPool.generated_pool.build do
31
+ add_file("message.proto", syntax: :proto3) do
32
+ # RPC 请求
33
+ add_message "RpcRequest" do
34
+ optional :func_code, :int32, 1
35
+ optional :data, :bytes, 2
36
+ optional :timestamp, :int64, 3
37
+ optional :request_id, :string, 4
38
+ end
39
+
40
+ # RPC 响应
41
+ add_message "RpcResponse" do
42
+ optional :status, :int32, 1
43
+ optional :data, :bytes, 2
44
+ optional :error_msg, :string, 3
45
+ optional :request_id, :string, 4
46
+ end
47
+
48
+ # 用户
49
+ add_message "User" do
50
+ optional :id, :int32, 1
51
+ optional :name, :string, 2
52
+ optional :email, :string, 3
53
+ repeated :tags, :string, 4
54
+ end
55
+
56
+ # 联系人
57
+ add_message "Contact" do
58
+ optional :wxid, :string, 1
59
+ optional :name, :string, 2
60
+ optional :remark, :string, 3
61
+ optional :contact_type, :int32, 4
62
+ end
63
+
64
+ # 联系人列表
65
+ add_message "ContactList" do
66
+ repeated :contacts, :message, 1, "Contact"
67
+ end
68
+
69
+ # 文本消息
70
+ add_message "TextMessage" do
71
+ optional :receiver, :string, 1
72
+ optional :content, :string, 2
73
+ optional :aters, :string, 3
74
+ end
75
+ end
76
+ end
77
+
78
+ # 获取消息类
79
+ RpcRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcRequest").msgclass
80
+ RpcResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcResponse").msgclass
81
+ User = Google::Protobuf::DescriptorPool.generated_pool.lookup("User").msgclass
82
+ Contact = Google::Protobuf::DescriptorPool.generated_pool.lookup("Contact").msgclass
83
+ ContactList = Google::Protobuf::DescriptorPool.generated_pool.lookup("ContactList").msgclass
84
+ TextMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("TextMessage").msgclass
85
+
86
+ puts "✅ Protobuf 消息类加载完成"
87
+ puts
88
+
89
+ # ============================================================================
90
+ # 2. 示例 1: 嵌套消息 - 获取联系人列表
91
+ # ============================================================================
92
+
93
+ puts "示例 1: 嵌套消息 - 获取联系人列表"
94
+ puts "=" * 70
95
+ puts
96
+
97
+ url1 = "tcp://127.0.0.1:15560"
98
+
99
+ # 服务器进程
100
+ server1_pid = fork do
101
+ server = NNG::Socket.new(:pair1)
102
+ server.listen(url1)
103
+ puts "[服务器] 监听: #{url1}"
104
+
105
+ # 接收 RPC 请求
106
+ request_data = server.recv
107
+ rpc_request = RpcRequest.decode(request_data)
108
+
109
+ puts "[服务器] 收到 RPC 调用:"
110
+ puts "[服务器] Function: 0x#{rpc_request.func_code.to_s(16)}"
111
+ puts "[服务器] Request ID: #{rpc_request.request_id}"
112
+ puts "[服务器] Timestamp: #{Time.at(rpc_request.timestamp)}"
113
+
114
+ # 构建联系人列表
115
+ contacts = ContactList.new(
116
+ contacts: [
117
+ Contact.new(wxid: "wxid_001", name: "张三", remark: "老同学", contact_type: 1),
118
+ Contact.new(wxid: "wxid_002", name: "李四", remark: "同事", contact_type: 1),
119
+ Contact.new(wxid: "chatroom_001", name: "技术交流群", remark: "", contact_type: 2)
120
+ ]
121
+ )
122
+
123
+ puts "[服务器] 构建响应: #{contacts.contacts.size} 个联系人"
124
+
125
+ # 编码嵌套消息
126
+ contacts_data = ContactList.encode(contacts)
127
+
128
+ # 构建 RPC 响应
129
+ rpc_response = RpcResponse.new(
130
+ status: 0,
131
+ data: contacts_data,
132
+ error_msg: "",
133
+ request_id: rpc_request.request_id
134
+ )
135
+
136
+ # 发送响应
137
+ server.send(RpcResponse.encode(rpc_response))
138
+ puts "[服务器] 响应已发送"
139
+
140
+ server.close
141
+ end
142
+
143
+ sleep 0.5
144
+
145
+ # 客户端
146
+ client1 = NNG::Socket.new(:pair1)
147
+ client1.dial(url1)
148
+ puts "[客户端] 连接: #{url1}"
149
+
150
+ # 构建 RPC 请求
151
+ rpc_request = RpcRequest.new(
152
+ func_code: 0x12, # FUNC_GET_CONTACTS
153
+ data: "",
154
+ timestamp: Time.now.to_i,
155
+ request_id: "req_#{Time.now.to_i}_001"
156
+ )
157
+
158
+ puts "[客户端] 发送 RPC 请求:"
159
+ puts "[客户端] Function: 0x#{rpc_request.func_code.to_s(16)}"
160
+ puts "[客户端] Request ID: #{rpc_request.request_id}"
161
+
162
+ # 发送请求
163
+ client1.send(RpcRequest.encode(rpc_request))
164
+
165
+ # 接收响应
166
+ response_data = client1.recv
167
+ rpc_response = RpcResponse.decode(response_data)
168
+
169
+ puts "[客户端] 收到 RPC 响应:"
170
+ puts "[客户端] Status: #{rpc_response.status}"
171
+ puts "[客户端] Request ID: #{rpc_response.request_id}"
172
+
173
+ if rpc_response.status == 0
174
+ # 解析嵌套的联系人列表
175
+ contacts = ContactList.decode(rpc_response.data)
176
+ puts "[客户端] 解析联系人列表 (#{contacts.contacts.size} 个):"
177
+
178
+ contacts.contacts.each_with_index do |contact, i|
179
+ puts "[客户端] #{i + 1}. #{contact.name} (#{contact.wxid})"
180
+ puts "[客户端] 备注: #{contact.remark}" unless contact.remark.empty?
181
+ puts "[客户端] 类型: #{contact.contact_type == 1 ? '好友' : '群聊'}"
182
+ end
183
+ else
184
+ puts "[客户端] 错误: #{rpc_response.error_msg}"
185
+ end
186
+
187
+ client1.close
188
+ Process.wait(server1_pid)
189
+
190
+ puts
191
+ puts
192
+
193
+ # ============================================================================
194
+ # 3. 示例 2: 发送文本消息
195
+ # ============================================================================
196
+
197
+ puts "示例 2: 发送文本消息"
198
+ puts "=" * 70
199
+ puts
200
+
201
+ url2 = "tcp://127.0.0.1:15561"
202
+
203
+ # 服务器进程
204
+ server2_pid = fork do
205
+ server = NNG::Socket.new(:pair1)
206
+ server.listen(url2)
207
+ puts "[服务器] 监听: #{url2}"
208
+
209
+ # 接收 RPC 请求
210
+ request_data = server.recv
211
+ rpc_request = RpcRequest.decode(request_data)
212
+
213
+ puts "[服务器] 收到 RPC 调用:"
214
+ puts "[服务器] Function: 0x#{rpc_request.func_code.to_s(16)}"
215
+
216
+ # 解析文本消息参数
217
+ text_msg = TextMessage.decode(rpc_request.data)
218
+ puts "[服务器] 解析文本消息:"
219
+ puts "[服务器] 接收者: #{text_msg.receiver}"
220
+ puts "[服务器] 内容: #{text_msg.content}"
221
+ puts "[服务器] @的人: #{text_msg.aters}" unless text_msg.aters.empty?
222
+
223
+ # 模拟发送消息
224
+ puts "[服务器] 发送消息..."
225
+ sleep 0.1
226
+ puts "[服务器] 消息发送成功"
227
+
228
+ # 构建响应
229
+ rpc_response = RpcResponse.new(
230
+ status: 0,
231
+ data: [1].pack('C'), # 返回 1 表示成功
232
+ error_msg: "",
233
+ request_id: rpc_request.request_id
234
+ )
235
+
236
+ server.send(RpcResponse.encode(rpc_response))
237
+ server.close
238
+ end
239
+
240
+ sleep 0.5
241
+
242
+ # 客户端
243
+ client2 = NNG::Socket.new(:pair1)
244
+ client2.dial(url2)
245
+ puts "[客户端] 连接: #{url2}"
246
+
247
+ # 构建文本消息
248
+ text_msg = TextMessage.new(
249
+ receiver: "wxid_001",
250
+ content: "Hello from NNG + Protobuf!",
251
+ aters: ""
252
+ )
253
+
254
+ # 编码为字节
255
+ text_msg_data = TextMessage.encode(text_msg)
256
+
257
+ # 构建 RPC 请求
258
+ rpc_request = RpcRequest.new(
259
+ func_code: 0x20, # FUNC_SEND_TXT
260
+ data: text_msg_data,
261
+ timestamp: Time.now.to_i,
262
+ request_id: "req_#{Time.now.to_i}_002"
263
+ )
264
+
265
+ puts "[客户端] 发送文本消息:"
266
+ puts "[客户端] 接收者: #{text_msg.receiver}"
267
+ puts "[客户端] 内容: #{text_msg.content}"
268
+
269
+ # 发送请求
270
+ client2.send(RpcRequest.encode(rpc_request))
271
+
272
+ # 接收响应
273
+ response_data = client2.recv
274
+ rpc_response = RpcResponse.decode(response_data)
275
+
276
+ puts "[客户端] 收到响应:"
277
+ if rpc_response.status == 0
278
+ puts "[客户端] ✅ 消息发送成功"
279
+ else
280
+ puts "[客户端] ❌ 发送失败: #{rpc_response.error_msg}"
281
+ end
282
+
283
+ client2.close
284
+ Process.wait(server2_pid)
285
+
286
+ puts
287
+ puts
288
+
289
+ # ============================================================================
290
+ # 总结
291
+ # ============================================================================
292
+
293
+ puts "=" * 70
294
+ puts "✅ 示例完成"
295
+ puts "=" * 70
296
+ puts
297
+ puts "关键技术点:"
298
+ puts
299
+ puts "1. 消息嵌套:"
300
+ puts " RpcRequest { data: ContactList { contacts: [Contact, ...] } }"
301
+ puts
302
+ puts "2. 序列化链:"
303
+ puts " 内层: ContactList.encode(contacts) → bytes"
304
+ puts " 外层: RpcRequest.encode(request) → bytes"
305
+ puts
306
+ puts "3. 反序列化链:"
307
+ puts " 外层: RpcRequest.decode(bytes) → request"
308
+ puts " 内层: ContactList.decode(request.data) → contacts"
309
+ puts
310
+ puts "4. 实际应用场景:"
311
+ puts " • RPC 框架 (如本例)"
312
+ puts " • 微服务通信"
313
+ puts " • 消息队列"
314
+ puts " • 分布式系统数据交换"
315
+ puts
316
+ puts "5. 优势:"
317
+ puts " ✅ 强类型约束"
318
+ puts " ✅ 自动编解码"
319
+ puts " ✅ 跨语言兼容"
320
+ puts " ✅ 高效序列化"
321
+ puts " ✅ 版本向后兼容"
322
+ puts
@@ -0,0 +1,340 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # NNG + Protocol Buffers 集成演示
5
+ # 展示如何将 Protobuf 消息通过 NNG 发送和接收
6
+
7
+ require 'google/protobuf'
8
+
9
+ puts "=" * 70
10
+ puts "NNG + Protocol Buffers 集成演示"
11
+ puts "=" * 70
12
+ puts
13
+
14
+ # ============================================================================
15
+ # 1. 定义 Protobuf 消息结构
16
+ # ============================================================================
17
+
18
+ puts "步骤 1: 定义 Protobuf 消息结构"
19
+ puts "-" * 70
20
+ puts
21
+
22
+ Google::Protobuf::DescriptorPool.generated_pool.build do
23
+ add_file("wcf_rpc.proto", syntax: :proto3) do
24
+ # RPC 请求消息
25
+ add_message "RpcRequest" do
26
+ optional :func_code, :int32, 1 # 功能码
27
+ optional :data, :bytes, 2 # 业务数据
28
+ optional :request_id, :string, 3 # 请求 ID
29
+ end
30
+
31
+ # RPC 响应消息
32
+ add_message "RpcResponse" do
33
+ optional :status, :int32, 1 # 状态码
34
+ optional :data, :bytes, 2 # 响应数据
35
+ optional :error_msg, :string, 3 # 错误消息
36
+ end
37
+
38
+ # 联系人信息
39
+ add_message "Contact" do
40
+ optional :wxid, :string, 1
41
+ optional :name, :string, 2
42
+ optional :remark, :string, 3
43
+ end
44
+
45
+ # 联系人列表
46
+ add_message "ContactList" do
47
+ repeated :contacts, :message, 1, "Contact"
48
+ end
49
+
50
+ # 文本消息
51
+ add_message "TextMessage" do
52
+ optional :receiver, :string, 1
53
+ optional :content, :string, 2
54
+ optional :aters, :string, 3
55
+ end
56
+ end
57
+ end
58
+
59
+ # 获取消息类
60
+ RpcRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcRequest").msgclass
61
+ RpcResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("RpcResponse").msgclass
62
+ Contact = Google::Protobuf::DescriptorPool.generated_pool.lookup("Contact").msgclass
63
+ ContactList = Google::Protobuf::DescriptorPool.generated_pool.lookup("ContactList").msgclass
64
+ TextMessage = Google::Protobuf::DescriptorPool.generated_pool.lookup("TextMessage").msgclass
65
+
66
+ puts "✅ 消息定义完成:"
67
+ puts " - RpcRequest (func_code, data, request_id)"
68
+ puts " - RpcResponse (status, data, error_msg)"
69
+ puts " - Contact (wxid, name, remark)"
70
+ puts " - ContactList (contacts[])"
71
+ puts " - TextMessage (receiver, content, aters)"
72
+ puts
73
+
74
+ # ============================================================================
75
+ # 2. 示例 1: 简单的请求-响应
76
+ # ============================================================================
77
+
78
+ puts "示例 1: 简单的 RPC 请求-响应"
79
+ puts "=" * 70
80
+ puts
81
+
82
+ # 客户端: 构建请求
83
+ request = RpcRequest.new(
84
+ func_code: 0x01, # FUNC_IS_LOGIN
85
+ data: "",
86
+ request_id: "req_001"
87
+ )
88
+
89
+ puts "📤 客户端构建请求:"
90
+ puts " Function Code: 0x#{request.func_code.to_s(16)}"
91
+ puts " Request ID: #{request.request_id}"
92
+ puts
93
+
94
+ # 序列化为二进制
95
+ request_binary = RpcRequest.encode(request)
96
+ puts "📦 序列化结果:"
97
+ puts " 大小: #{request_binary.bytesize} bytes"
98
+ puts " 十六进制: #{request_binary.unpack('H*').first[0, 40]}..."
99
+ puts
100
+
101
+ # 模拟通过 NNG 发送 (实际代码: socket.send(request_binary))
102
+ puts "🌐 通过 NNG 发送: socket.send(request_binary)"
103
+ puts
104
+
105
+ # 服务器: 接收并反序列化
106
+ # 模拟从 NNG 接收 (实际代码: response_binary = socket.recv)
107
+ puts "📥 服务器接收并解析:"
108
+ received_request = RpcRequest.decode(request_binary)
109
+ puts " Function Code: 0x#{received_request.func_code.to_s(16)}"
110
+ puts " Request ID: #{received_request.request_id}"
111
+ puts
112
+
113
+ # 服务器: 构建响应
114
+ response = RpcResponse.new(
115
+ status: 0,
116
+ data: [1].pack('C'), # 返回 1 表示已登录
117
+ error_msg: ""
118
+ )
119
+
120
+ puts "📤 服务器构建响应:"
121
+ puts " Status: #{response.status} (成功)"
122
+ puts
123
+
124
+ # 序列化响应
125
+ response_binary = RpcResponse.encode(response)
126
+ puts "📦 序列化响应: #{response_binary.bytesize} bytes"
127
+ puts
128
+
129
+ # 模拟通过 NNG 发送响应
130
+ puts "🌐 通过 NNG 发送响应: socket.send(response_binary)"
131
+ puts
132
+
133
+ # 客户端: 接收并解析响应
134
+ received_response = RpcResponse.decode(response_binary)
135
+ puts "📥 客户端接收响应:"
136
+ puts " Status: #{received_response.status}"
137
+ puts " Is Login: #{received_response.data.unpack('C').first == 1}"
138
+ puts
139
+ puts
140
+
141
+ # ============================================================================
142
+ # 3. 示例 2: 嵌套消息 - 获取联系人列表
143
+ # ============================================================================
144
+
145
+ puts "示例 2: 嵌套消息 - 获取联系人列表"
146
+ puts "=" * 70
147
+ puts
148
+
149
+ # 客户端: 发送获取联系人请求
150
+ get_contacts_request = RpcRequest.new(
151
+ func_code: 0x12, # FUNC_GET_CONTACTS
152
+ data: "",
153
+ request_id: "req_002"
154
+ )
155
+
156
+ request_binary = RpcRequest.encode(get_contacts_request)
157
+ puts "📤 客户端发送请求: FUNC_GET_CONTACTS (#{request_binary.bytesize} bytes)"
158
+ puts
159
+
160
+ # 服务器: 构建联系人列表
161
+ contacts = ContactList.new(
162
+ contacts: [
163
+ Contact.new(wxid: "wxid_001", name: "张三", remark: "老同学"),
164
+ Contact.new(wxid: "wxid_002", name: "李四", remark: "同事"),
165
+ Contact.new(wxid: "wxid_003", name: "王五", remark: ""),
166
+ Contact.new(wxid: "chatroom_001", name: "技术交流群", remark: "")
167
+ ]
168
+ )
169
+
170
+ puts "🏗️ 服务器构建联系人列表:"
171
+ contacts.contacts.each_with_index do |contact, i|
172
+ puts " #{i + 1}. #{contact.name} (#{contact.wxid})"
173
+ puts " 备注: #{contact.remark}" unless contact.remark.empty?
174
+ end
175
+ puts
176
+
177
+ # 序列化联系人列表 (内层消息)
178
+ contacts_binary = ContactList.encode(contacts)
179
+ puts "📦 序列化联系人列表: #{contacts_binary.bytesize} bytes"
180
+ puts
181
+
182
+ # 构建 RPC 响应 (外层消息,包含内层数据)
183
+ contacts_response = RpcResponse.new(
184
+ status: 0,
185
+ data: contacts_binary, # 嵌套的联系人列表
186
+ error_msg: ""
187
+ )
188
+
189
+ response_binary = RpcResponse.encode(contacts_response)
190
+ puts "📦 序列化 RPC 响应: #{response_binary.bytesize} bytes"
191
+ puts " (包含嵌套的联系人列表)"
192
+ puts
193
+
194
+ # 客户端: 接收并解析
195
+ puts "📥 客户端接收并解析:"
196
+
197
+ # 第一层: 解析 RPC 响应
198
+ rpc_resp = RpcResponse.decode(response_binary)
199
+ puts " RPC Status: #{rpc_resp.status}"
200
+
201
+ # 第二层: 解析嵌套的联系人列表
202
+ contact_list = ContactList.decode(rpc_resp.data)
203
+ puts " 联系人数量: #{contact_list.contacts.size}"
204
+ puts
205
+
206
+ puts "📋 解析结果:"
207
+ contact_list.contacts.each_with_index do |contact, i|
208
+ puts " #{i + 1}. #{contact.name}"
209
+ puts " WXID: #{contact.wxid}"
210
+ puts " 备注: #{contact.remark}" unless contact.remark.empty?
211
+ end
212
+ puts
213
+ puts
214
+
215
+ # ============================================================================
216
+ # 4. 示例 3: 发送文本消息
217
+ # ============================================================================
218
+
219
+ puts "示例 3: 发送文本消息"
220
+ puts "=" * 70
221
+ puts
222
+
223
+ # 客户端: 构建文本消息
224
+ text_msg = TextMessage.new(
225
+ receiver: "wxid_001",
226
+ content: "Hello from NNG + Protobuf!",
227
+ aters: ""
228
+ )
229
+
230
+ puts "📝 客户端构建文本消息:"
231
+ puts " 接收者: #{text_msg.receiver}"
232
+ puts " 内容: #{text_msg.content}"
233
+ puts
234
+
235
+ # 序列化文本消息
236
+ text_msg_binary = TextMessage.encode(text_msg)
237
+ puts "📦 序列化文本消息: #{text_msg_binary.bytesize} bytes"
238
+ puts
239
+
240
+ # 构建 RPC 请求 (包含文本消息)
241
+ send_text_request = RpcRequest.new(
242
+ func_code: 0x20, # FUNC_SEND_TXT
243
+ data: text_msg_binary,
244
+ request_id: "req_003"
245
+ )
246
+
247
+ request_binary = RpcRequest.encode(send_text_request)
248
+ puts "📦 序列化 RPC 请求: #{request_binary.bytesize} bytes"
249
+ puts "🌐 通过 NNG 发送: socket.send(request_binary)"
250
+ puts
251
+
252
+ # 服务器: 接收并解析
253
+ puts "📥 服务器接收并解析:"
254
+ recv_request = RpcRequest.decode(request_binary)
255
+ puts " Function Code: 0x#{recv_request.func_code.to_s(16)}"
256
+
257
+ # 解析嵌套的文本消息
258
+ recv_text_msg = TextMessage.decode(recv_request.data)
259
+ puts " 接收者: #{recv_text_msg.receiver}"
260
+ puts " 内容: #{recv_text_msg.content}"
261
+ puts
262
+
263
+ # 服务器: 发送消息并响应
264
+ puts "📨 服务器发送消息..."
265
+ send_response = RpcResponse.new(
266
+ status: 0,
267
+ data: [1].pack('C'), # 1 = 发送成功
268
+ error_msg: ""
269
+ )
270
+
271
+ response_binary = RpcResponse.encode(send_response)
272
+ puts "📤 服务器响应: 发送成功"
273
+ puts
274
+
275
+ # 客户端: 接收响应
276
+ final_response = RpcResponse.decode(response_binary)
277
+ puts "📥 客户端收到响应:"
278
+ if final_response.status == 0
279
+ puts " ✅ 消息发送成功"
280
+ else
281
+ puts " ❌ 发送失败: #{final_response.error_msg}"
282
+ end
283
+ puts
284
+ puts
285
+
286
+ # ============================================================================
287
+ # 5. 总结
288
+ # ============================================================================
289
+
290
+ puts "=" * 70
291
+ puts "✅ 演示完成"
292
+ puts "=" * 70
293
+ puts
294
+ puts "实际使用 NNG 的代码示例:"
295
+ puts
296
+ puts " require 'nng'"
297
+ puts " require 'google/protobuf'"
298
+ puts
299
+ puts " # 客户端"
300
+ puts " client = NNG::Socket.new(:pair1)"
301
+ puts " client.dial('tcp://127.0.0.1:10086')"
302
+ puts
303
+ puts " # 构建并发送 Protobuf 请求"
304
+ puts " request = RpcRequest.new(func_code: 0x12, data: '', request_id: 'req_001')"
305
+ puts " request_binary = RpcRequest.encode(request)"
306
+ puts " client.send(request_binary)"
307
+ puts
308
+ puts " # 接收并解析 Protobuf 响应"
309
+ puts " response_binary = client.recv"
310
+ puts " response = RpcResponse.decode(response_binary)"
311
+ puts
312
+ puts " # 解析嵌套的业务数据"
313
+ puts " contacts = ContactList.decode(response.data)"
314
+ puts
315
+ puts " client.close"
316
+ puts
317
+ puts "关键技术点:"
318
+ puts
319
+ puts "1. 消息嵌套:"
320
+ puts " RpcRequest/Response.data 字段 (bytes 类型) 可存储任意 Protobuf 消息"
321
+ puts
322
+ puts "2. 序列化链:"
323
+ puts " 业务消息 → encode → bytes → RPC 消息 → encode → bytes → NNG 发送"
324
+ puts
325
+ puts "3. 反序列化链:"
326
+ puts " NNG 接收 → bytes → decode → RPC 消息 → bytes → decode → 业务消息"
327
+ puts
328
+ puts "4. 优势:"
329
+ puts " ✅ 类型安全 - 编译时检查"
330
+ puts " ✅ 高效编码 - 比 JSON 小 50%+"
331
+ puts " ✅ 跨语言 - 与 Python/Java/Go/C++ 互通"
332
+ puts " ✅ 版本兼容 - 可安全添加/删除字段"
333
+ puts " ✅ 自动验证 - 自动检查必填字段"
334
+ puts
335
+ puts "5. 实际应用场景:"
336
+ puts " • WeChatFerry RPC 通信"
337
+ puts " • 微服务间调用"
338
+ puts " • 分布式系统消息传递"
339
+ puts " • 客户端-服务器协议"
340
+ puts