first commit

This commit is contained in:
lisang 2024-06-27 21:04:09 +08:00
commit 3661cfa8e7
25 changed files with 593 additions and 0 deletions

35
.gitignore vendored Normal file
View File

@ -0,0 +1,35 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
info.text

22
README.md Normal file
View File

@ -0,0 +1,22 @@
# 手写RPC框架
> RPC:让你像是在做本地调用一样去调用一个远程服务器上的方法
## RPC相关图示
RPC简单示意图
![RPC简单示意图](./doc/rpc简示图.png)
RPC时序图
![RPC时序图](./doc/rpc时序图.png)
手写RPC简易流程图
![手写RPC简易流程图](./doc/rpc简易流程.png)
## RPC需要解决的内容
- 必须要有服务暴露
- 必须要有远程代理对象
- 通信
- 序列化与反序列化
- IO

BIN
doc/rpc时序图.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

BIN
doc/rpc简易流程.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
doc/rpc简示图.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

35
pom.xml Normal file
View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shockkid</groupId>
<artifactId>rpc</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<modules>
<module>rpc-api</module>
<module>rpc-server</module>
<module>rpc-client</module>
</modules>
<name>rpc</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

29
rpc-api/pom.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shockkid</groupId>
<artifactId>rpc-api</artifactId>
<version>1.0</version>
<name>rpc-api</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,13 @@
package com.shockkid;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}

View File

@ -0,0 +1,9 @@
package com.shockkid;
/**
* @auther lisang
* @date 2024/6/27 17:02
**/
public interface HelloServer {
public String sayHello(String content);
}

View File

@ -0,0 +1,57 @@
package com.shockkid;
import java.io.Serializable;
import java.util.Arrays;
/**
* @auther lisang
* @date 2024/6/27 16:59
**/
public class RpcRequest implements Serializable {
private String className;
private String methodName;
private Object[] parameters;
private Class[] types;
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParameters() {
return parameters;
}
public void setParameters(Object[] parameters) {
this.parameters = parameters;
}
public Class[] getTypes() {
return types;
}
public void setTypes(Class[] types) {
this.types = types;
}
@Override
public String toString() {
return "RpcRequest{" +
"className='" + className + '\'' +
", methodName='" + methodName + '\'' +
", parameters=" + Arrays.toString(parameters) +
", types=" + Arrays.toString(types) +
'}';
}
}

View File

@ -0,0 +1,20 @@
package com.shockkid;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}

34
rpc-client/pom.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shockkid</groupId>
<artifactId>rpc-client</artifactId>
<version>1.0</version>
<name>rpc-client</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.shockkid</groupId>
<artifactId>rpc-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,13 @@
package com.shockkid;
/**
* Hello world!
*/
public class Client {
public static void main(String[] args) {
RpcProxyClient rpcProxyClient = new RpcProxyClient();
HelloServer helloServer = rpcProxyClient.clientProxy(HelloServer.class, "localhost", 8081);
Object obj = helloServer.sayHello("lisang");
System.out.println(obj.toString());
}
}

View File

@ -0,0 +1,30 @@
package com.shockkid;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @auther lisang
* @date 2024/6/27 19:51
**/
public class RemoteInvocationHandler implements InvocationHandler {
private String host;
private int port;
public RemoteInvocationHandler(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
RpcRequest request = new RpcRequest();
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameters(args);
request.setTypes(method.getParameterTypes());
RpcNetTransport rpcNetTransport = new RpcNetTransport(host, port);
return rpcNetTransport.send(request);
}
}

View File

@ -0,0 +1,66 @@
package com.shockkid;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
/**
* @auther lisang
* @date 2024/6/27 19:56
**/
public class RpcNetTransport {
private String host;
private int port;
public RpcNetTransport(String host, int port) {
this.host = host;
this.port = port;
}
private Socket newSocket() throws IOException {
System.out.println("开始建立一个连接");
Socket socket = null;
socket = new Socket(host, port);
return socket;
}
public Object send(RpcRequest request) {
Socket socket = null;
Object result = null;
ObjectOutputStream os = null;
ObjectInputStream is = null;
try {
socket = newSocket();
os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(request);
is = new ObjectInputStream(socket.getInputStream());
result = is.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}

View File

@ -0,0 +1,15 @@
package com.shockkid;
import java.lang.reflect.Proxy;
/**
* @auther lisang
* @date 2024/6/27 20:07
**/
public class RpcProxyClient {
public <T> T clientProxy(Class interfacecls, String host, int port) {
return (T) Proxy.newProxyInstance(interfacecls.getClassLoader(),
new Class[]{interfacecls},
new RemoteInvocationHandler(host, port));
}
}

View File

@ -0,0 +1,20 @@
package com.shockkid;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}

34
rpc-server/pom.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.shockkid</groupId>
<artifactId>rpc-server</artifactId>
<version>1.0</version>
<name>rpc-server</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.shockkid</groupId>
<artifactId>rpc-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,12 @@
package com.shockkid;
/**
* @auther lisang
* @date 2024/6/27 17:03
**/
public class HelloServerImpl implements HelloServer {
@Override
public String sayHello(String content) {
return "shockkid " + content + " say hello";
}
}

View File

@ -0,0 +1,54 @@
package com.shockkid;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
/**
* @auther lisang
* @date 2024/6/27 17:12
**/
public class ProcessorHandler implements Runnable {
Socket socket = null;
Object service = null;
public ProcessorHandler(Socket socket, Object service) {
this.socket = socket;
this.service = service;
}
@Override
public void run() {
ObjectInputStream is = null;
ObjectOutputStream os = null;
try {
is = new ObjectInputStream(socket.getInputStream());
RpcRequest rpcRequest = (RpcRequest) is.readObject();
Object result = invoke(rpcRequest);
os = new ObjectOutputStream(socket.getOutputStream());
os.writeObject(result);
os.flush();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private Object invoke(RpcRequest request) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = Class.forName(request.getClassName());
Object[] args = request.getParameters();
Method method = clazz.getMethod(request.getMethodName(), request.getTypes());
Object obj = method.invoke(service, args);
return obj;
}
}

View File

@ -0,0 +1,30 @@
package com.shockkid;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @auther lisang
* @date 2024/6/27 17:06
**/
public class RpcProxyServer {
private ExecutorService executorService = Executors.newCachedThreadPool();
public void publisher(Object server,int prot) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(prot);
while (true) {
Socket socket = serverSocket.accept();
executorService.execute(new ProcessorHandler(socket, server));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,12 @@
package com.shockkid;
/**
* Hello world!
*/
public class Server {
public static void main(String[] args) {
HelloServer helloServer = new HelloServerImpl();
RpcProxyServer rpcProxyServer = new RpcProxyServer();
rpcProxyServer.publisher(helloServer, 8081);
}
}

View File

@ -0,0 +1,20 @@
package com.shockkid;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}

View File

@ -0,0 +1,13 @@
package com.shockkid;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}

View File

@ -0,0 +1,20 @@
package com.shockkid;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}