├── .idea
├── .gitignore
├── compiler.xml
├── jarRepositories.xml
├── misc.xml
└── vcs.xml
├── README.md
├── Simple-RPC.iml
├── Simple-RPC.ipr
├── Simple-RPC.iws
├── assets
├── Screen Shot 2022-05-29 at 14.24.21-3816076.png
└── Screen Shot 2022-05-29 at 14.24.39.png
├── pom.xml
├── src
├── main
│ └── java
│ │ └── rpc
│ │ └── tomstillcoding
│ │ └── com
│ │ ├── IDL
│ │ ├── Hello
│ │ │ ├── HelloRequest.java
│ │ │ ├── HelloResponse.java
│ │ │ └── HelloService.java
│ │ └── Ping
│ │ │ ├── PingRequest.java
│ │ │ ├── PingResponse.java
│ │ │ └── PingService.java
│ │ └── core
│ │ ├── client
│ │ ├── RpcClientProxy.java
│ │ └── RpcClientTransfer.java
│ │ ├── codec
│ │ ├── RpcRequestBody.java
│ │ └── RpcResponseBody.java
│ │ ├── rpc_protocol
│ │ ├── RpcRequest.java
│ │ └── RpcResponse.java
│ │ └── server
│ │ ├── RpcServer.java
│ │ └── RpcServerWorker.java
└── test
│ └── java
│ ├── client
│ └── TestClient.java
│ ├── server
│ ├── HelloServiceImpl.java
│ ├── PingServiceImpl.java
│ └── TestServer.java
│ └── test
│ ├── Employee.java
│ └── Test.java
└── target
├── classes
└── rpc
│ └── tomstillcoding
│ └── com
│ ├── IDL
│ ├── Hello
│ │ ├── HelloRequest.class
│ │ ├── HelloResponse.class
│ │ └── HelloService.class
│ └── Ping
│ │ ├── PingRequest.class
│ │ ├── PingResponse.class
│ │ └── PingService.class
│ └── core
│ ├── client
│ ├── RpcClientProxy.class
│ └── RpcClientTransfer.class
│ ├── codec
│ ├── RpcRequestBody$RpcRequestBodyBuilder.class
│ ├── RpcRequestBody.class
│ ├── RpcResponseBody$RpcResponseBodyBuilder.class
│ └── RpcResponseBody.class
│ ├── rpc_protocol
│ ├── RpcRequest$RpcRequestBuilder.class
│ ├── RpcRequest.class
│ ├── RpcResponse$RpcResponseBuilder.class
│ └── RpcResponse.class
│ └── server
│ ├── RpcServer.class
│ └── RpcServerWorker.class
└── test-classes
├── client
└── TestClient.class
├── server
├── HelloServiceImpl.class
├── PingServiceImpl.class
└── TestServer.class
└── test
├── Employee.class
└── Test.class
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simple-RPC
2 | 用Java手撸一个简单的RPC框架|一个写C++的在看完gRPC后用Java手撸了个简单RPC框架
3 | # 使用方式
4 | 用IDEA打开后配置Maven,右键点击pom.xml,重新加载项目(Reload Project)
5 | 然后直接运行服务器程序和客户端程序
6 |
7 | 带你手撸简单RPC框架|一个写C++的在看完gRPC后用Java快速手撸了个简单RPC框架
8 |
9 | # 目录
10 |
11 | 今天的视频分三部分:
12 |
13 | 1、介绍RPC是什么
14 |
15 | 2、介绍谷歌gRPC的Go语言使用
16 |
17 | 3、用Java手撸一个最简单的RPC框架
18 |
19 | 今天聊到的所有东西都会开源,在看完视频后,你可以照着文档,以及看看源代码,就能明白RPC的核心内容,也可以在这个简单RPC框架代码上补充各种组件,最后写到自己的简历上,最重要的目的是,撸一套RPC框架,能让你掌握RPC的核心功能实现。
20 |
21 | (等录完视频,我就去剪头发 做核酸 看MSI了)
22 |
23 | # 介绍RPC
24 |
25 |
26 |
27 | # gRPC使用
28 |
29 | grpc,就像是Dubbo一样,都是RPC框架,可能你听得云里雾里的,先看看具体怎么用吧
30 |
31 | 定义hello.proto文件:
32 |
33 | proto是啥,IDL,IDL是什么,接口描述语言(Interface description language,缩写IDL),什么意思?不重要,重要的是,客户端在调用服务器的方法的时候,用IDL确定了两者的方法名、参数、返回值.
34 |
35 | 下面我们编写hello.proto文件
36 |
37 | ```protobuf
38 | syntax = "proto3"; // 版本声明,使用Protocol Buffers v3版本
39 | package pb; // 包名
40 |
41 | // 定义服务
42 | service Greeter {
43 | // SayHello 方法
44 | rpc SayHello (HelloRequest) returns (HelloResponse) {}
45 | }
46 |
47 | // 请求消息
48 | message HelloRequest {
49 | string name = 1;
50 | }
51 |
52 | // 响应消息
53 | message HelloResponse {
54 | string reply = 1;
55 | }
56 | ```
57 |
58 | ```bash
59 | protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative hello.proto
60 | ```
61 |
62 | 通过.proto文件,用grpc的工具,生成我们需要的库代码,然后用Go编写客户端和服务端程序。
63 |
64 | 不会Go语言?无所谓,都是面向对象语言,调用方法=方法名+参数+返回值,看得懂就够了,看不懂,花一分钟查下语法就看懂了
65 |
66 |
67 |
68 | 服务端代码:收到客户端请求,拿到需要调用的函数(SayHello)+参数(HelloRequest),调用本地的函数实现,将返回值(HelloResponse)返回给客户端
69 |
70 | ```go
71 | package main
72 |
73 | import (
74 | "context"
75 | "fmt"
76 | "hello_server/pb"
77 | "net"
78 |
79 | "google.golang.org/grpc"
80 | )
81 |
82 | // ----------------------- 实现pb中的接口 Start ------------------------
83 | type server struct {
84 | pb.UnimplementedGreeterServer
85 | }
86 | func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
87 | return &pb.HelloResponse{Reply: "Hello " + in.Name}, nil
88 | }
89 | // ----------------------- 实现pb中的接口 End ------------------------
90 |
91 | func main() {
92 | // 1. 监听本地的8972端口
93 | lis, err := net.Listen("tcp", ":8972")
94 | if err != nil {
95 | fmt.Printf("failed to listen: %v", err)
96 | return
97 | }
98 |
99 | // 2. 创建grpc服务器并注册服务(注册服务就是说,将pb接口的方法实现并register)
100 | rpcServer := grpc.NewServer()
101 | pb.RegisterGreeterServer(rpcServer, &server{})
102 |
103 | // 3. 启动grpc服务器
104 | err = rpcServer.Serve(lis)
105 | if err != nil {
106 | fmt.Printf("failed to serve: %v", err)
107 | return
108 | }
109 | }
110 | ```
111 |
112 | 客户端代码:调用函数(SayHello),传入参数(HelloRequest),获得返回值(HelloResponse)
113 |
114 | ```go
115 | package main
116 |
117 | import (
118 | "context"
119 | "flag"
120 | "log"
121 | "time"
122 |
123 | "hello_client/pb"
124 |
125 | "google.golang.org/grpc"
126 | "google.golang.org/grpc/credentials/insecure"
127 | )
128 |
129 | // ----------------------- 一会儿需要用到的变量 Start ------------------------
130 | const (
131 | defaultName = "world"
132 | )
133 |
134 | var (
135 | addr = flag.String("addr", "127.0.0.1:8972", "the address to connect to")
136 | name = flag.String("name", defaultName, "Name to greet")
137 | )
138 | // ----------------------- 一会儿需要用到的变量 End ------------------------
139 |
140 | func main() {
141 | flag.Parse()
142 | // 连接到server端,此处禁用安全传输
143 | conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
144 | if err != nil {
145 | log.Fatalf("did not connect: %v", err)
146 | }
147 | defer conn.Close()
148 |
149 | // ------------------------- rpc调用 start -----------------------------------
150 | // 创建grpcClient
151 | rpcClient := pb.NewGreeterClient(conn)
152 |
153 | // 设置上下文(没事不用管)
154 | ctx, cancel := context.WithTimeout(context.Background(), time.Second)
155 | defer cancel()
156 |
157 | // 执行rpc调用
158 | r, err := rpcClient.SayHello(ctx, &pb.HelloRequest{Name: *name})
159 |
160 | // 错误处理
161 | if err != nil {
162 | log.Fatalf("could not greet: %v", err)
163 | }
164 | log.Printf("Greeting: %s", r.GetReply())
165 | // ------------------------- rpc调用 end -----------------------------------
166 | }
167 | ```
168 |
169 |
170 |
171 | 总结:
172 |
173 | proto文件(IDL)定义方法、参数、返回值,使用工具直接生成go可以用的库。
174 |
175 | Server:创建**grpcServer对象**,注册服务(也就是自己定义的方法,针对proto文件方法的实现),**启动服务器**。
176 |
177 | Client:创建**grpcClient对象(给出服务ip+port地址)**,用grpcClient对象调用服务(也就是调用proto文件里面声明的方法),然后打印返回的结果。
178 |
179 |
180 |
181 | # 手撸Java RPC框架
182 |
183 | 因此,我们要用Java手撸一个最简单的RPC,按照上面的说法,应该要实现的是:
184 |
185 | 框架:
186 |
187 | 1. 接口文件,定义了方法名、参数、返回值,供客户端和服务端使用
188 | 2. RPC框架,让客户端和服务端可以使用框架,达到**本地调用,远端执行**的目的
189 |
190 | 测试:
191 |
192 | 1. 写一个TestServer可执行程序,注册方法的实现后,使用rpcServer进行监听并处理rpc调用
193 | 2. 写一个TestClient可执行程序,使用rpcClient进行发起rpc调用,并打印rpc调用结果
194 |
195 |
196 |
197 |
198 |
199 | ### 第一步:写IDL文件
200 |
201 | IDL.Hello的内容直接编写完毕。
202 |
203 | 按照grpc的方式,编写接口HelloService,以及里面的消息体HelloRequest和HelloResponse,客户端和服务器都使用这同一套接口
204 |
205 | ### 第二步:编写RPC协议
206 |
207 | RpcRequest和RpcResponse都是RPC协议,RPC协议包括header和body两部分,header我们用String表示,body我们用序列化后的byte[]流表示,这里的字节流的序列化的方式可以是Java的序列化方式,可以换成JSON序列化方式,也可以用Thrift、PB序列化方式,为了简单,我们这次直接用Java的序列化方式。
208 |
209 | 然后body中被序列化的内容,因为是codec层的工作,放在了codec包中,RPCReuqest要调用一个方法,需要知道接口名、方法名、参数、参数类型,因此把这些东西放进RpcRequestBody中即可,后面把它序列化后房价RpcRequest的body字节流中;同理,RPCResponse 的body中,只需要一个被序列化后的Java Object即可。
210 |
211 | ### 第三步:分析
212 |
213 | 我们的rpcClient要执行一个函数hello,传入参数HelloRequest,然后返回HelloResponse。
214 |
215 | 整个流程就是:客户端获得rpcService对象,使用rpcService对象执行hello方法,那么rpcService底层实现就发送一条RpcRequest协议(对比HTTP协议)把:要执行的接口名+方法名+参数类型+具体参数序列化后,放进RpcRequest协议的body字节流中,然后给RpcRequest加上header,发给服务端,服务端解析出Rpc协议的body(对比HTTP协议解析body)中的接口名、方法名等,直接调用本地的接口的实现,然后将返回值包装成一条RpcResponse消息,发送给客户端即可,rpcService底层将该response消息解析,从body中拿到(也是对比HTTP解析body)返回值,然后返回给客户端。
216 |
217 | ### 第四步:客户端实现(动态代理)
218 |
219 | 客户端方面,客户端本地只有IDL.Hello中的内容,没有方法的具体实现,也就是说要调用一个没有实现的接口,显然,我们使用Java反射的动态代理特性,实例化一个接口,将调用接口方法“代理”给InvocationHandler中的invoke来执行,在Invoke中获取到接口名、方法名等包装成Rpc协议,发送给服务端,然后等待服务端返回。
220 |
221 | ### 第五步:服务端实现(反射调用)
222 |
223 | 服务端方面,本地需要实现接口的方法,然后在启动监听网络之前注册所有的接口,当消息到来的时候,根据RpcRequestBody中的接口名拿到接口对象,然后用反射的方式调用即可,将调用结果包装成RpcResponse,发送给客户端。
224 |
225 | ### 第六步:测试
226 |
227 | 编写测试用例
228 |
229 | 一共两个接口,HelloService和PingService,HelloService有两个方法:hello和hi,PingService有一个方法:ping
230 |
231 | ### 总结
232 |
233 | 事实上一个完整的RPC框架不仅包含上面的内容,还要提供很多功能,比如说
234 |
235 | 服务发现:客户端怎么找到能够调用rpc的服务器的ip和端口?
236 |
237 | 服务治理:整个rpc的运行怎么可靠,比如说客户端请求太多,一台服务器不顶用,IO打满了,再加一台服务器?
238 |
239 | 服务注册:服务器怎么才能把自己能够handle的接口告诉客户端,不然自己都不能处理,客户端调用接口,调了也是失败
240 |
241 | 编解码:比如上面body中我们是直接用的Java序列化,那要是跨平台怎么办,客户端用Java写,服务端用Go写,Go又不能处理Java序列化,对吧,而且编解码性能、编码后的字节数量也是很重要的一些东西
242 |
243 | RPC协议:协议的字段有很多的,协议版本、传输方式、序列化方式、连接个数等等
244 |
245 |
246 |
247 | 所以,今天讲的这个东西不过是一个RPC的最简化Demo,帮大家理解rpc的原理,按照多层模型去设计与实现,后面往这个架子上面搭东西,或者去学习真正的RPC框架是比较有帮助的,祝大家周末快乐!
248 |
--------------------------------------------------------------------------------
/Simple-RPC.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
75 |
76 |
--------------------------------------------------------------------------------
/Simple-RPC.ipr:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/Simple-RPC.iws:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
--------------------------------------------------------------------------------
/assets/Screen Shot 2022-05-29 at 14.24.21-3816076.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/assets/Screen Shot 2022-05-29 at 14.24.21-3816076.png
--------------------------------------------------------------------------------
/assets/Screen Shot 2022-05-29 at 14.24.39.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/assets/Screen Shot 2022-05-29 at 14.24.39.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | Simple-RPC
9 | 1.0-SNAPSHOT
10 |
11 |
12 | org.projectlombok
13 | lombok
14 | 1.18.24
15 |
16 |
17 |
18 |
19 |
20 | 11
21 | 11
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Hello/HelloRequest.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Hello;
2 |
3 |
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 |
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class HelloRequest implements Serializable {
12 | private String name;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Hello/HelloResponse.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Hello;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class HelloResponse implements Serializable {
12 | private String msg;
13 | }
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Hello/HelloService.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Hello;
2 |
3 | public interface HelloService {
4 | HelloResponse hello(HelloRequest request);
5 | HelloResponse hi(HelloRequest request);
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Ping/PingRequest.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Ping;
2 |
3 |
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 |
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class PingRequest implements Serializable {
12 | private String name;
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Ping/PingResponse.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Ping;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class PingResponse implements Serializable {
12 | private String msg;
13 | }
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/IDL/Ping/PingService.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.IDL.Ping;
2 |
3 | public interface PingService {
4 | PingResponse ping(PingRequest request);
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/client/RpcClientProxy.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.client;
2 |
3 | import rpc.tomstillcoding.com.core.codec.RpcRequestBody;
4 | import rpc.tomstillcoding.com.core.codec.RpcResponseBody;
5 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcRequest;
6 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcResponse;
7 |
8 | import java.io.ByteArrayInputStream;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.ObjectInputStream;
11 | import java.io.ObjectOutputStream;
12 | import java.lang.reflect.InvocationHandler;
13 | import java.lang.reflect.Method;
14 | import java.lang.reflect.Proxy;
15 |
16 | public class RpcClientProxy implements InvocationHandler {
17 | @SuppressWarnings("unchecked")
18 | public T getService(Class clazz) {
19 | return (T) Proxy.newProxyInstance(
20 | clazz.getClassLoader(),
21 | new Class>[]{clazz},
22 | this
23 | );
24 | }
25 |
26 | @Override
27 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
28 |
29 | // 1、将调用所需信息编码成bytes[],即有了调用编码【codec层】
30 | RpcRequestBody rpcRequestBody = RpcRequestBody.builder()
31 | .interfaceName(method.getDeclaringClass().getName())
32 | .methodName(method.getName())
33 | .paramTypes(method.getParameterTypes())
34 | .parameters(args)
35 | .build();
36 |
37 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
38 | ObjectOutputStream oos = new ObjectOutputStream(baos);
39 | oos.writeObject(rpcRequestBody);
40 | byte[] bytes = baos.toByteArray();
41 |
42 | // 2、创建RPC协议,将Header、Body的内容设置好(Body中存放调用编码)【protocol层】
43 | RpcRequest rpcRequest = RpcRequest.builder()
44 | .header("version=1")
45 | .body(bytes)
46 | .build();
47 |
48 | // 3、发送RpcRequest,获得RpcResponse
49 | RpcClientTransfer rpcClient = new RpcClientTransfer();
50 | RpcResponse rpcResponse = rpcClient.sendRequest(rpcRequest);
51 |
52 | // 4、解析RpcResponse,也就是在解析rpc协议【protocol层】
53 | String header = rpcResponse.getHeader();
54 | byte[] body = rpcResponse.getBody();
55 | if (header.equals("version=1")) {
56 | // 将RpcResponse的body中的返回编码,解码成我们需要的对象Object并返回【codec层】
57 | ByteArrayInputStream bais = new ByteArrayInputStream(body);
58 | ObjectInputStream ois = new ObjectInputStream(bais);
59 | RpcResponseBody rpcResponseBody = (RpcResponseBody) ois.readObject();
60 | Object retObject = rpcResponseBody.getRetObject();
61 | return retObject;
62 | }
63 | return null;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/client/RpcClientTransfer.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.client;
2 |
3 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcRequest;
4 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcResponse;
5 |
6 | import java.io.IOException;
7 | import java.io.ObjectInputStream;
8 | import java.io.ObjectOutputStream;
9 | import java.net.Socket;
10 |
11 | // 传入protocol层的RpcRequest,输出protocol层的RpcResponse
12 | public class RpcClientTransfer {
13 |
14 | public RpcResponse sendRequest(RpcRequest rpcRequest) {
15 | try (Socket socket = new Socket("localhost", 9000)) {
16 | // 发送【transfer层】
17 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
18 | ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
19 | objectOutputStream.writeObject(rpcRequest);
20 | objectOutputStream.flush();
21 |
22 | RpcResponse rpcResponse = (RpcResponse) objectInputStream.readObject();
23 |
24 | return rpcResponse;
25 |
26 | } catch (IOException | ClassNotFoundException e) {
27 | e.printStackTrace();
28 | return null;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/codec/RpcRequestBody.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.codec;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | @Data
9 | @Builder
10 | // 调用编码
11 | public class RpcRequestBody implements Serializable {
12 | private String interfaceName;
13 | private String methodName;
14 | private Object[] parameters;
15 | private Class>[] paramTypes;
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/codec/RpcResponseBody.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.codec;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Builder;
5 | import lombok.Data;
6 |
7 | import java.io.Serializable;
8 |
9 | @Data
10 | @Builder
11 | // 返回值编码
12 | public class RpcResponseBody implements Serializable {
13 | private Object retObject;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/rpc_protocol/RpcRequest.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.rpc_protocol;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | @Data
9 | @Builder
10 | // Serializable:对象变成可传输的字节序列
11 | public class RpcRequest implements Serializable {
12 | // 协议头部分
13 | private String header;
14 | // 协议体部分
15 | private byte[] body;
16 |
17 |
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/rpc_protocol/RpcResponse.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.rpc_protocol;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | @Data
9 | @Builder
10 | // 为什么要有泛型?因为返回的对象是各种各样类型的
11 | // Serializable:对象变成可传输的字节序列
12 | public class RpcResponse implements Serializable {
13 | // 协议头部分
14 | private String header;
15 |
16 | // 协议体部分
17 | private byte[] body;
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/server/RpcServer.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.server;
2 |
3 | import java.io.IOException;
4 | import java.net.ServerSocket;
5 | import java.net.Socket;
6 | import java.util.HashMap;
7 | import java.util.concurrent.*;
8 |
9 | public class RpcServer {
10 | private final ExecutorService threadPool;
11 | // interfaceName -> interfaceImplementation object
12 | private final HashMap registeredService;
13 |
14 | public RpcServer() {
15 |
16 | int corePoolSize = 5;
17 | int maximumPoolSize = 50;
18 | long keepAliveTime = 60;
19 | BlockingQueue workingQueue = new ArrayBlockingQueue<>(100);
20 | ThreadFactory threadFactory = Executors.defaultThreadFactory();
21 | this.threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workingQueue, threadFactory);
22 | this.registeredService = new HashMap();
23 | }
24 |
25 | // 参数service就是interface的implementation object
26 | public void register(Object service) {
27 | registeredService.put(service.getClass().getInterfaces()[0].getName(), service);
28 | }
29 |
30 | public void serve(int port) {
31 | try (ServerSocket serverSocket = new ServerSocket(port)){
32 | System.out.println("server starting...");
33 | Socket handleSocket;
34 | while ((handleSocket = serverSocket.accept()) != null) {
35 | System.out.println("client connected, ip:" + handleSocket.getInetAddress());
36 | threadPool.execute(new RpcServerWorker(handleSocket, registeredService));
37 | }
38 | } catch (IOException e) {
39 | e.printStackTrace();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/rpc/tomstillcoding/com/core/server/RpcServerWorker.java:
--------------------------------------------------------------------------------
1 | package rpc.tomstillcoding.com.core.server;
2 |
3 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcRequest;
4 | import rpc.tomstillcoding.com.core.codec.RpcRequestBody;
5 | import rpc.tomstillcoding.com.core.rpc_protocol.RpcResponse;
6 | import rpc.tomstillcoding.com.core.codec.RpcResponseBody;
7 |
8 | import java.io.*;
9 | import java.lang.reflect.InvocationTargetException;
10 | import java.lang.reflect.Method;
11 | import java.net.Socket;
12 | import java.util.HashMap;
13 |
14 | public class RpcServerWorker implements Runnable{
15 |
16 | private Socket socket;
17 | private HashMap registeredService;
18 |
19 | public RpcServerWorker(Socket socket, HashMap registeredService) {
20 | this.socket = socket;
21 | this.registeredService = registeredService;
22 | }
23 |
24 | @Override
25 | public void run() {
26 | try {
27 | ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
28 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
29 |
30 | // 1、Transfer层获取到RpcRequest消息【transfer层】
31 | RpcRequest rpcRequest = (RpcRequest) objectInputStream.readObject();
32 |
33 | // 2、解析版本号,并判断【protocol层】
34 | if (rpcRequest.getHeader().equals("version=1")) {
35 |
36 | // 3、将rpcRequest中的body部分解码出来变成RpcRequestBody【codec层】
37 | byte[] body = rpcRequest.getBody();
38 | ByteArrayInputStream bais = new ByteArrayInputStream(body);
39 | ObjectInputStream ois = new ObjectInputStream(bais);
40 | RpcRequestBody rpcRequestBody = (RpcRequestBody) ois.readObject();
41 |
42 | // 调用服务
43 | Object service = registeredService.get(rpcRequestBody.getInterfaceName());
44 | Method method = service.getClass().getMethod(rpcRequestBody.getMethodName(), rpcRequestBody.getParamTypes());
45 | Object returnObject = method.invoke(service, rpcRequestBody.getParameters());
46 |
47 | // 1、将returnObject编码成bytes[]即变成了返回编码【codec层】
48 | RpcResponseBody rpcResponseBody = RpcResponseBody.builder()
49 | .retObject(returnObject)
50 | .build();
51 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
52 | ObjectOutputStream oos = new ObjectOutputStream(baos);
53 | oos.writeObject(rpcResponseBody);
54 | byte[] bytes = baos.toByteArray();
55 |
56 | // 2、将返回编码作为body,加上header,生成RpcResponse协议【protocol层】
57 | RpcResponse rpcResponse = RpcResponse.builder()
58 | .header("version=1")
59 | .body(bytes)
60 | .build();
61 | // 3、发送【transfer层】
62 | objectOutputStream.writeObject(rpcResponse);
63 | objectOutputStream.flush();
64 | }
65 |
66 | } catch (IOException | ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
67 | e.printStackTrace();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/test/java/client/TestClient.java:
--------------------------------------------------------------------------------
1 | package client;
2 |
3 | import rpc.tomstillcoding.com.IDL.Hello.HelloRequest;
4 | import rpc.tomstillcoding.com.IDL.Hello.HelloResponse;
5 | import rpc.tomstillcoding.com.IDL.Hello.HelloService;
6 | import rpc.tomstillcoding.com.core.client.RpcClientProxy;
7 |
8 | public class TestClient {
9 | public static void main(String[] args) {
10 | // 获取RpcService
11 | RpcClientProxy proxy = new RpcClientProxy();
12 | HelloService helloService = proxy.getService(HelloService.class);
13 | // 构造出请求对象HelloRequest
14 | HelloRequest helloRequest = new HelloRequest("tom");
15 | // rpc调用并返回结果对象HelloResponse
16 | HelloResponse helloResponse = helloService.hello(helloRequest);
17 | // 从HelloResponse中获取msg
18 | String helloMsg = helloResponse.getMsg();
19 | // 打印msg
20 | System.out.println(helloMsg);
21 |
22 | // 调用hi方法
23 | HelloResponse hiResponse = helloService.hi(helloRequest);
24 | String hiMsg = hiResponse.getMsg();
25 | System.out.println(hiMsg);
26 |
27 | // 调用ping方法
28 | // PingService pingService = proxy.getService(PingService.class);
29 | // PingRequest pingRequest = new PingRequest("tom");
30 | // PingResponse pingResponse = pingService.ping(pingRequest);
31 | // String pingMsg = pingResponse.getMsg();
32 | // System.out.println(pingMsg);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/server/HelloServiceImpl.java:
--------------------------------------------------------------------------------
1 | package server;
2 |
3 | import rpc.tomstillcoding.com.IDL.Hello.HelloRequest;
4 | import rpc.tomstillcoding.com.IDL.Hello.HelloResponse;
5 | import rpc.tomstillcoding.com.IDL.Hello.HelloService;
6 |
7 | public class HelloServiceImpl implements HelloService {
8 | @Override
9 | public HelloResponse hello(HelloRequest request) {
10 | String name = request.getName();
11 | String retMsg = "hello: " + name;
12 | HelloResponse response = new HelloResponse(retMsg);
13 | return response;
14 | }
15 |
16 | @Override
17 | public HelloResponse hi(HelloRequest request) {
18 | String name = request.getName();
19 | String retMsg = "hi: " + name;
20 | HelloResponse response = new HelloResponse(retMsg);
21 | return response;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/server/PingServiceImpl.java:
--------------------------------------------------------------------------------
1 | package server;
2 |
3 | import rpc.tomstillcoding.com.IDL.Hello.HelloRequest;
4 | import rpc.tomstillcoding.com.IDL.Hello.HelloResponse;
5 | import rpc.tomstillcoding.com.IDL.Hello.HelloService;
6 | import rpc.tomstillcoding.com.IDL.Ping.PingRequest;
7 | import rpc.tomstillcoding.com.IDL.Ping.PingResponse;
8 | import rpc.tomstillcoding.com.IDL.Ping.PingService;
9 |
10 | public class PingServiceImpl implements PingService {
11 |
12 | @Override
13 | public PingResponse ping(PingRequest request) {
14 | String name = request.getName();
15 | String retMsg = "pong: " + name;
16 | PingResponse response = new PingResponse(retMsg);
17 | return response;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/server/TestServer.java:
--------------------------------------------------------------------------------
1 | package server;
2 |
3 | import rpc.tomstillcoding.com.IDL.Hello.HelloService;
4 | import rpc.tomstillcoding.com.IDL.Ping.PingService;
5 | import rpc.tomstillcoding.com.core.server.RpcServer;
6 |
7 | public class TestServer {
8 | public static void main(String[] args) {
9 | RpcServer rpcServer = new RpcServer(); // 真正的rpc server
10 | HelloService helloService = new HelloServiceImpl(); // 包含需要处理的方法的对象
11 | rpcServer.register(helloService); // 向rpc server注册对象里面的所有方法
12 | // PingService pingService = new PingServiceImpl();
13 | // rpcServer.register(pingService);
14 |
15 | rpcServer.serve(9000);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/test/Employee.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | public class Employee implements java.io.Serializable
4 | {
5 | public String name;
6 | public String address;
7 | public transient int SSN;
8 | public int number;
9 | public void mailCheck()
10 | {
11 | System.out.println("Mailing a check to " + name
12 | + " " + address);
13 | }
14 | }
--------------------------------------------------------------------------------
/src/test/java/test/Test.java:
--------------------------------------------------------------------------------
1 | package test;
2 |
3 | import java.io.*;
4 |
5 | public class Test
6 | {
7 | public static void main(String [] args)
8 | {
9 |
10 |
11 | Employee e = null;
12 | try
13 | {
14 | FileInputStream fileIn = new FileInputStream("/Users/thomas/Desktop/test.txt");
15 | ObjectInputStream in = new ObjectInputStream(fileIn);
16 | e = (Employee) in.readObject();
17 | in.close();
18 | fileIn.close();
19 | }catch(IOException i)
20 | {
21 | i.printStackTrace();
22 | return;
23 | }catch(ClassNotFoundException c)
24 | {
25 | System.out.println("Employee class not found");
26 | c.printStackTrace();
27 | return;
28 | }
29 | System.out.println("Deserialized Employee...");
30 | System.out.println("Name: " + e.name);
31 | System.out.println("Address: " + e.address);
32 | System.out.println("SSN: " + e.SSN);
33 | System.out.println("Number: " + e.number);
34 | }
35 | }
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloRequest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloRequest.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloResponse.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloResponse.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Hello/HelloService.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingRequest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingRequest.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingResponse.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingResponse.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingService.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/IDL/Ping/PingService.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/client/RpcClientProxy.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/client/RpcClientProxy.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/client/RpcClientTransfer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/client/RpcClientTransfer.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/codec/RpcRequestBody$RpcRequestBodyBuilder.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/codec/RpcRequestBody$RpcRequestBodyBuilder.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/codec/RpcRequestBody.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/codec/RpcRequestBody.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/codec/RpcResponseBody$RpcResponseBodyBuilder.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/codec/RpcResponseBody$RpcResponseBodyBuilder.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/codec/RpcResponseBody.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/codec/RpcResponseBody.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcRequest$RpcRequestBuilder.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcRequest$RpcRequestBuilder.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcRequest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcRequest.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcResponse$RpcResponseBuilder.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcResponse$RpcResponseBuilder.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcResponse.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/rpc_protocol/RpcResponse.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/server/RpcServer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/server/RpcServer.class
--------------------------------------------------------------------------------
/target/classes/rpc/tomstillcoding/com/core/server/RpcServerWorker.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/classes/rpc/tomstillcoding/com/core/server/RpcServerWorker.class
--------------------------------------------------------------------------------
/target/test-classes/client/TestClient.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/client/TestClient.class
--------------------------------------------------------------------------------
/target/test-classes/server/HelloServiceImpl.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/server/HelloServiceImpl.class
--------------------------------------------------------------------------------
/target/test-classes/server/PingServiceImpl.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/server/PingServiceImpl.class
--------------------------------------------------------------------------------
/target/test-classes/server/TestServer.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/server/TestServer.class
--------------------------------------------------------------------------------
/target/test-classes/test/Employee.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/test/Employee.class
--------------------------------------------------------------------------------
/target/test-classes/test/Test.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tomstillcoding/Simple-RPC/4d3dc61f73bc462722123e47da9fded7c204d693/target/test-classes/test/Test.class
--------------------------------------------------------------------------------