千家信息网

rpc通信是如何进行的

发表于:2024-10-18 作者:千家信息网编辑
千家信息网最后更新 2024年10月18日,这篇文章主要介绍了rpc通信是如何进行的的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇rpc通信是如何进行的文章都会有所收获,下面我们一起来看看吧。RPC(Remote
千家信息网最后更新 2024年10月18日rpc通信是如何进行的

这篇文章主要介绍了rpc通信是如何进行的的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇rpc通信是如何进行的文章都会有所收获,下面我们一起来看看吧。

RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

基本概念

  • RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务

  • 本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定。

  • 远程过程调用:上述操作的过程中,如果addAge()这个方法在服务端,执行函数的函数体在远程机器上,如何告诉机器需要调用这个方法呢?

今天,我们就通过一个实例代码进行演示,一步步的查看,rpc的通信是如何进行的,有兴趣的朋友可以把代码进行实现,自己debug一下,查看每一步的传参

package com.mashibing.rpc.common;

import java.io.Serializable;

public class User implements Serializable {
private static final long serialVersionUID = 1L;

private Integer id;
private String name;

public User(Integer id, String name) {
this.id = id;
this.name = name;
}

public Integer getId() {
return id;
}

public String getName() {
return name;
}

public void setId(Integer id) {
this.id = id;
}

public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
package com.mashibing.rpc.common;

public interface IUserService {
public User findUserById(Integer id);
}
package com.mashibing.rpc01;


import com.mashibing.rpc.common.IUserService;
import com.mashibing.rpc.common.User;

public class UserServiceImpl implements IUserService {
@Override
public User findUserById(Integer id) {
return new User(id, "Alice");
}
}
package com.mashibing.rpc01;

import com.mashibing.rpc.common.User;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

public class Client {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1", 8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);

s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();

DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(id, name);

System.out.println(user);

dos.close();
s.close();
}
}
package com.mashibing.rpc02;

import com.mashibing.rpc.common.User;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;

public class Stub {
public User findUserById(Integer id) throws Exception {
Socket s = new Socket("127.0.0.1", 8888);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);

s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();

DataInputStream dis = new DataInputStream(s.getInputStream());
int receivedId = dis.readInt();
String name = dis.readUTF();
User user = new User(id, name);

dos.close();
s.close();
return user;
}
}
package com.mashibing.rpc03;

import com.mashibing.rpc.common.IUserService;
import com.mashibing.rpc.common.User;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
* 而且Client的调用显得不是很合理(Stub里只有findById的代码),如果有个findByName的新方法,那么就又得重新改进
* 下面这种写法解决了方法增加的问题
*/

public class Stub {
public static IUserService getStub() {
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1", 8888);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeInt(123);

s.getOutputStream().write(baos.toByteArray());
s.getOutputStream().flush();

DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(id, name);

dos.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[] {IUserService.class}, h);
return (IUserService)o;
}
}
package com.mashibing.rpc04;

import com.mashibing.rpc.common.IUserService;
import com.mashibing.rpc.common.User;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;

/**
* 但是这里仅仅实现了findByUserId的方法代理,如果要实现其他方法的代理该怎么做呢?
* 这里就要从协议层做出改进
*
* 服务器端也要做出对应处理
*/

public class Stub {
public static IUserService getStub() {
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Socket s = new Socket("127.0.0.1", 8888);

ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());

String methodName = method.getName();
Class[] parametersTypes = method.getParameterTypes();
oos.writeUTF(methodName);
oos.writeObject(parametersTypes);
oos.writeObject(args);
oos.flush();


DataInputStream dis = new DataInputStream(s.getInputStream());
int id = dis.readInt();
String name = dis.readUTF();
User user = new User(id, name);

oos.close();
s.close();
return user;
}
};
Object o = Proxy.newProxyInstance(IUserService.class.getClassLoader(), new Class[] {IUserService.class}, h);
return (IUserService)o;
}




}
package com.mashibing.rpc04;

import com.mashibing.rpc.common.IUserService;
import com.mashibing.rpc.common.User;

import java.io.*;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(8888);
while (running) {
Socket s = ss.accept();
process(s);
s.close();
}
ss.close();
}

private static void process(Socket s) throws Exception {
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
ObjectInputStream oos = new ObjectInputStream(in);
DataOutputStream dos = new DataOutputStream(out);

String methodName = oos.readUTF();
Class[] parameterTypes = (Class[])oos.readObject();
Object[] args = (Object[])oos.readObject();

IUserService service = new UserServiceImpl();
Method method = service.getClass().getMethod(methodName, parameterTypes);
User user = (User)method.invoke(service, args);



dos.writeInt(user.getId());
dos.writeUTF(user.getName());
dos.flush();
}
}

返回值用Object封装,支持任意类型

关于"rpc通信是如何进行的"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"rpc通信是如何进行的"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

0