欢迎登上头条:Java Little Margo
周一到周日早上9:30!下午三点半!精品技术文章请准时发送!
精品学习资料获取通道见文末
用手把手写RPC给你。
什么是1.1 RPC
定义:远程过程调用协议(RPC)——远程过程调用协议,RPC协议假定存在某些传输协议(如TCP或UDP),以便在通信程序之间传递信息数据。在OSI网络通信模型中,RPC跨越传输层和应用层,RPC使开发应用程序(包括网络分布式多程序)变得更加容易。
我的理解:最好以客户端/服务器交互模式查看RPC,而不是以协议查看,但RPC必须基于TCP或其他通信协议。
现在,让我们看一下RPC调用过程中涉及的通信详细信息。
服务消费者(客户端)调用将作为本地调用调用服务。(1)客户端存根负责在收到调用后将方法、参数等汇编成可以进行网络传输的消息正文。(2)客户端存根找到服务地址,向服务端发送消息。(3)server stub收到消息后对其进行解码。(4)服务器存根根据解码结果调用本地服务。(5)本地服务将运行,结果将返回到serverstub。(6)server stub将返回结果包装成消息发送给消费者。(7)客户端存根接收和解码消息。(8)服务消费者取得了最终结果。(9)RPC的目标是封装2-8个步骤,使用户对这些细节透明。
1.2手动实施
1.2.1首先创建null接口以实现序列化接口
public interface irpc service extends serial izable {
}
1.2.2创建需要远程调用的接口及其接口实现类
public interface ihello service extends irpc service {
String sayhi(字串名称,字串讯息);
}
public class hello service implements ihello service {
private static final long serial versionuid=146468468464364698 l;
@Override
Public string sayhi(字串名称,字串讯息){
Return new stringbuilder()。append ('hi ~!'))。append('')。append (message)。tostring();
}
}
1.2.3需要编写服务器端,以执行服务注册(接口注册),接收客户端的调用参数,并返回调用请求执行结果
注意:此处没有用dom4j解析概要文件注册接口。有时间的朋友可以再加一层。
Public interface Server {
//插座端口
Int PORT=8080
//服务器端启动
void start()throws io exception;
//停止服务器端
void stop();
/* *
*服务登记
*-服务接口外部暴露接口
* -内部实施类
*/
Void regist(Class)?extends irpc service service interface,class?扩展irpcservice impl
);}
public class ServerCenter implements Server{
/**线程池 接收客户端调用**/
private static ThreadPoolexecutor executor = new ThreadPoolExecutor(5, 20, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(10));
/**服务注册缓存**/
public static final Map<String,Class<?>> serviceRegistry = new HashMap<>();
/**
* 启动服务
*/
@Override
public void start() throws IOException {
ServerSocket server = new ServerSocket();
(new InetSocketAddress(PORT));
try {
while(true){
execu(new ServiceTask()));
}
} finally {
();
}
}
/**
* 停止服务
*/
@Override
public void stop() {
execu();
}
/**
* 注册服务
*/
@Override
public void regist(Class<? extends IRpcService> serviceInterface, Class<? extends IRpcService> impl) {
(), impl);
}
private static class ServiceTask implements Runnable{
Socket client = null;
public ServiceTask(Socket client) {
= client;
}
@Override
public void run() {
ObjectInputStream input = null;
ObjectoutputStream output = null;
try {
input = new ObjectInputStream());
String serviceName = in();
String methodName = in();
Class<?>[] parameterTypes = (Class<?>[]) in();
Object[] arguments = (Object[]) in();
Class<?> serviceClass = (serviceName);
if(serviceClass == null){
throw new ClassNotFoundException(serviceName + "not found");
}
Method method = (methodName, parameterTypes);
Object result = me(), arguments);
//将执行结果反序列化 通过socket返给客户端
output = new ObjectOutputStream());
ou(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(input != null){
try {
in();
} catch (IOException e) {
e.printStackTrace();
}
}
if(output != null){
try {
out();
} catch (IOException e) {
e.printStackTrace();
}
}
if(client != null){
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws Exception {
ServerCenter center = new ServerCenter();
cen HelloServiceImpl().getClass());
cen();
}
}
1.2.4 写一个客户端,用动态代理 获取被代理接口的 各种参数 传输给 服务端,接收返回结果,打印到控制台
public class Client {
@SuppressWarnings("unchecked")
public static <T extends IRpcService>T getRemoteProxyObj(final Class<? extends IRpcService> serviceInterface,final InetSocketAddress addr){
return (T) Proxy.newProxyInstance(), new Class<?>[]{serviceInterface}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket socket = null;
ObjectOutputStream output = null;
ObjectInputStream input = null;
try {
//1.创建Socket客户端,根据指定地址连接远程服务提供者
socket = new Socket();
(addr);
//2.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者
output = new ObjectOutputStream());
ou());
ou());
ou());
ou(args);
//3.同步阻塞等待服务器返回应答 获取应答后返回
input = new ObjectInputStream());
return in();
} finally{
if(socket != null){
();
}
if(output != null){
out();
}
if(input != null){
in();
}
}
}
});
}
}
1.2.5 测试
注:测试之前 需要开启服务端
public class RpcTest {
public static void main(String[] args) throws IOException {
IHelloService service = Client.getRemoteProxyObj, new InetSocketAddress(8080));
Sy("张三", "新年快乐!"));
}
}
就这样我们实现了一个简陋的RPC
本文意在通过实现简单的RPC,去真正意义上对RPC框架的实现原理有初步的了解,而不是人云亦云。
此RPC实现有诸多缺点,但是 我们只要明白RPC的基座 其他的RPC框架只是完善基座以及扩展而已 。
rpc简单实现git代码地址
封面图源网络,侵权删除)
私信头条号,发送:“资料”,获取更多“秘制” 精品学习资料
如有收获,请帮忙转发,您的鼓励是作者最大的动力,谢谢!
一大波微服务、分布式、高并发、高可用的原创系列文章正在路上,
欢迎关注头条号:java小马哥
周一至周日早九点半!下午三点半!精品技术文章准时送上!!!
十余年BAT架构经验倾囊相授
精品推荐:Java架构师,Java直播课 |打造一线互联网java架构师
地址:
(复制链接到浏览器即可)
> 看到这里,说明你喜欢本文,你的转发,是对我最大的鼓励!在看亦是支持↓