The so-called RPC is a remote method call, or simply by mq,tcp,http or the network protocol you write to transmit what I want to call the other side of the interface, the other side processing and then return the results to me. That's a simple process.
At runtime, a client-to-server RPC call, with an internal operation of roughly 10 steps, is as follows:
1 . Calling client handle; executing transfer parameters
2. call the Local system kernel to send network messages
3. Message delivery to remote host
4. The server handle gets the message and obtains the parameter
5. Perform remote procedures
6 . The execution process returns the result to the server handle
7, the server handle returns the result, call the remote system kernel
8. The message is returned to the local host
9. client handle receives message from kernel
The customer receives the data returned by the handle
Before an article simple RPC socket implementation we through the socket communication implementation of a simple RPC call, next we implement a simple RPC call process based on Netty, of course, there are many imperfect places, only for reference to learn RPC use.
First, define the entity class for message passing
public class ClassInfo implements Serializable {private static final long Serialversionuid = -8970942815543515064l;privat E string classname;//class name private String methodname;//function name private class<?>[] types;//parameter type private object[] objects;//parameter list 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 class<?>[] GetTypes () {return types;} public void Settypes (class<?>[] types) {this.types = types;} Public object[] GetObjects () {return objects;} public void SetObjects (object[] objects) {this.objects = objects;}}
Second, create the service side of the Netty operation, and the specific operation
(1) Service side
public class Rpcserver {private int port;public rpcserver (int port) {this.port = port;} public void Start () {Eventloopgroup bossgroup = new Nioeventloopgroup (); Eventloopgroup Workergroup = new Nioeventloopgroup (); try {serverbootstrap serverbootstrap = new Serverbootstrap (). Group (Bossgroup, Workergroup). Channel (Nioserversocketchannel.class). LocalAddress (Port). Childhandler (New Channelinitializer<socketchannel> () {@Overrideprotected void Initchannel (Socketchannel ch) throws Exception { Channelpipeline pipeline = Ch.pipeline (); Pipeline.addlast (New Lengthfieldbasedframedecoder (Integer.max_value, 0, 4, 0, 4)); Pipeline.addlast (New Lengthfieldprepender (4)); Pipeline.addlast ("encoder", New Objectencoder ()); Pipeline.addlast ("Decoder", New Objectdecoder (Integer.max_value, classresolvers.cachedisabled (null))); Pipeline.addlast (New Invokerhandler ()); }}). Option (Channeloption.so_backlog, $). Childoption (Channeloption.so_keepalive, true); Channelfuture future = Serverbootstrap.bind (port). sync (); System.out.println ("Server start listen at" + port); Future.channel (). Closefuture (). sync (); } catch (Exception e) {bossgroup.shutdowngracefully (); Workergroup.shutdowngracefully ();}} public static void Main (string[] args) throws Exception {int port; if (Args.length > 0) {port = Integer.parseint (Args[0]); } else {port = 8080; } new Rpcserver (port). Start (); } }
(2) service-side operation, by the server we see the specific data transmission operation is serialized, the specific operation or relatively simple, is to obtain the information sent over, so that you can get the class name through reflection, according to the function name and parameter values, perform specific operations, the execution results sent to the client.
public class Invokerhandler extends Channelinboundhandleradapter {public static concurrenthashmap<string, Object > classmap = new concurrenthashmap<string,object> (), @Override public void Channelread (Channelhandlercontext CTX, Object msg) throws Exception {ClassInfo ClassInfo = (classinfo) msg; Object Claszz = null;if (!classmap.containskey (Classinfo.getclassname ())) {try {claszz = Class.forName ( Classinfo.getclassname ()). newinstance (); Classmap.put (Classinfo.getclassname (), CLASZZ);} catch (Instantiationexception | illegalaccessexception | ClassNotFoundException e) {e.printstacktrace ();}} else {claszz = Classmap.get (Classinfo.getclassname ());} method = Claszz.getclass (). GetMethod (Classinfo.getmethodname (), classinfo.gettypes ()); Object result = Method.invoke (Claszz, classinfo.getobjects ()); Ctx.write (result); Ctx.flush (); Ctx.close (); } @Override public void Exceptioncaught (Channelhandlercontext ctx, throwable cause) throws Exception {cause.printstacktrace (); Ctx.close (); } }
Third, the client, through the proxy mechanism to trigger the remote call
(1) The client, when executing a specific function, invokes a remote operation that sends the class, function, and parameter information of the specific operation to the server
public class RpcProxy {@SuppressWarnings ("unchecked") public static <T> T Create (Object target) {return (T) proxy.ne Wproxyinstance (Target.getclass (). getClassLoader (), Target.getclass (). Getinterfaces (), new Invocationhandler () {@ Overridepublic object Invoke (Object proxy, Method method, object[] args) throws Throwable {ClassInfo ClassInfo = new ClassI NFO (); Classinfo.setclassname (Target.getclass (). GetName ()); Classinfo.setmethodname (Method.getname ()); Classinfo.setobjects (args); Classinfo.settypes (Method.getparametertypes ()); Resulthandler Resulthandler = new Resulthandler (); Eventloopgroup Group = new Nioeventloopgroup (); try {Bootstrap b = new Bootstrap (); B.group (Group). Channel (niosocketchannel.class). Option (Channeloption.tcp_nodelay, True) . Handler (new channelinitializer<socketchannel> () {@Override public voi D initchannel (Socketchannel ch) throws Exception { Channelpipeline pipeline = Ch.pipeline (); Pipeline.addlast ("Framedecoder", New Lengthfieldbasedframedecoder (Integer.max_value, 0, 4, 0, 4)); Pipeline.addlast ("Frameencoder", New Lengthfieldprepender (4)); Pipeline.addlast ("encoder", New Objectencoder ()); Pipeline.addlast ("Decoder", New Objectdecoder (Integer.max_value, classresolvers.cachedisabled (null))); Pipeline.addlast ("handler", Resulthandler); } }); Channelfuture future = B.connect ("localhost", 8080). sync (); Future.channel (). Writeandflush (ClassInfo). sync (); Future.channel (). Closefuture (). sync (); } finally {group.shutdowngracefully (); } return Resulthandler.getresponse ();}});}}
(2) Gets the result value returned by the remote call
public class Resulthandler extends Channelinboundhandleradapter {private Object response; Public Object GetResponse () { return response; } @Override public void Channelread (Channelhandlercontext ctx, Object msg) throws Exception { response=msg; SYSTEM.OUT.PRINTLN ("Client received the message returned by the server:" + msg); } @Override public void Exceptioncaught (Channelhandlercontext ctx, Throwable cause) throws Exception { SYSTEM.OUT.PRINTLN ("Client exception is General"); } }
IV. interfaces, implementation classes, and main operations
Interface:
Public interface Hellorpc {string Hello (string name);}
Implementation class:
public class Hellorpcimpl implements HELLORPC {@Overridepublic string hello (string name) {return "Hello" +name;}}
Main operation:
public class Main {public static void main (String [] args) {Hellorpc hellorpc = new Hellorpcimpl (); hellorpc = Rpcproxy.crea Te (HELLORPC); System.err.println (Hellorpc.hello ("RPC"));}}
Full Code address GitHub
Netty implementation of simple RPC implementation