LANDPC完结原理,自行实现

前言

小李:“胖子,上头叫你对接本身的数额好了从未?”

胖子:“那是你的事,你都不提供数据源,作者咋接?”

小李:“你想要什么样的数据源?”

胖子:“小编想要三个调用容易点的!”

小李:“作者这一个数据源是在linux平台使用docker封装发表的,webapi的什么?”

胖子:“也行,那项目工期快用完了,你得提供api封装sdk,此外小编那边对质量有供给的!”

小李:“webapi多好,基于json各种平台都能联网,质量还不易的!”

胖子:“笔者只关心自个儿的事情,不是自个儿的事体代码,多一行小编都不想码,不然没按时实现算你的!此外用webapi到时候请求量一大,到时候端口用完了,连接不了那锅也得你背!”

小李:“我@##¥%*#¥@#&##@……”

LANDPC完结原理,自行实现。面对胖子这个理由,小李心里面即便一千0只草泥马在跑马,不过项目依然要成功是不?此外胖子说的也创造!小李作为2个在C#下侵淫多年老鸟,十分的快想出一个主意——rpc!首先当然是选wcf,这几个巨硬的商号级产品在连忙支付上巳了配备上坑爹了几许,针对客户端的过渡真的要命快。小李仔细一探讨wcf
service 发现脚下在linux下玩不了,心里面又是了一阵@##¥%*#¥@#&##@……

胖子:“小李纠结啥,要不就弄个三方的搞一下算了,即便出事了,你大概都已经离职了,怕啥……”

望着胖子一脸猥琐的神情,小李那是1个气呀,就怪自已平日牛逼吹上天,那时候怎么好怂呢,一咬牙:“你放心,误不了你的事!”。小李一边回复,心里面起先盘算着自行实现七个效应简易,质量高效,使用简易的rpc了。

  上边小李与胖子的现象,在付出的时候也是经典案例,回到正题来:本身觉得rpc首若是:调用方法及参数系列化、socket传输、调用方法及参数反系列化、映射到地头并应用与请求相同流程回复客户端的一套方案。个中关键点不难分析首要有:体系化与反种类化、高质量tcp、远程方法反转、客户端代码生成多个地点;tcp照旧利用iocp好了,其余接着一一分析。

福特ExplorerPC落成原理(HSF、dubbo) 从头初步(一),hsfdubbo

前言

 

久违了很久微博,固然看了原先写的众多事物感觉好天真,可是还是认为应该把一些谈得来觉得可行的事物和我们分享。废话不多说,今后始于进入正题。

事先的六年工作经历,呆过了有的大商厦,每个在大商厦呆过的人相应通晓,在二个重型应用中穿梭的充实业务和功能,还有基于品质的设想,使得广大基础服务必须开始展览模块化,从而让各子系统方便使用而不是种种系统再次再落到实处一套,也得以使恐怕变成瓶颈的基础意义能够独立进行扩大,比如(以电商系统举例)用户消息保管、交易管理焦点、商品质量管理理理核心等等。
 在rpc发展最初,服务拓展模块块以往,各个子系统、模块达成的技术五花八门,如:hessian、WebService、Socket、http等开展交互调用,种种子系统里面包车型客车交互情势和章程不联合,使得各系统间很难很好的整合。并且那一个点子还关乎超时、加密解密、参数的传递等各样难点。
 在那种意况下,hsf、dubbo那种高品质rpc中间件现身了。
 将来自家就已最不难易行的点子从头发轫讲起当中的原理。

自小编将分为叁个星罗棋布为我们进行解剖

壹 、凯雷德PC达成原理(HSF、dubbo) 从头初阶(一)

二、帕杰罗PC完成原理(HSF、dubbo)颁发三个劳动与订阅二个服务**(三)**

***三、PAJEROPC达成原理(HSF、dubbo)**zookeeper进行集群配置管理(二)*

四、冠道PC达成原理(HSF、dubbo)netty替换java socket(四)

*五、待补充*

NO.1  TCP传输协议

何以选拔TCP作为传输协议?HTTP在TCP的上一层,位于应用层,TCP位于互连网层,以越往底层越快的规律,小编就只是多解释为啥采用tcp作为传输协议了。
那么在项目中我们怎么选择tcp进行调用呢?直接上个例子代码:

socket服务端:

 

import java.net.*;
import java.io.*;

/**
 * socket编程之:简单socket server
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketServer {
    private ServerSocket serverSocket;
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public SocketServer() {
        try {
            serverSocket = new ServerSocket(9999);
            while (true) {
                // 此处会阻塞,后面会讲到nio的作用 
                socket = serverSocket.accept();
                in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                out = new PrintWriter(socket.getOutputStream(), true);
                String line = in.readLine();
                // 打印出来看看结果
                System.out.println("line:" + line);

                // 返回给client端,通知我已收到数据
                out.println("you input is :" + line);
                out.close();
                in.close();
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketServer();
    }
}

 

scoket客户端:

 

import java.io.*;
import java.net.*;

/**
 * socket编程之:简单socket client
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketClient {
    private Socket socket;
    private BufferedReader in;
    private PrintWriter out;

    public SocketClient() {
        try {
            socket = new Socket("127.0.0.1", 9999);
            in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            // 向服务端写数据
            BufferedReader line = new BufferedReader(new InputStreamReader(
                    System.in));

            out.println(line.readLine());
            line.close();
            // 打印出来服务端发回来的回执
            System.out.println(in.readLine());

            in.close();
            out.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketClient();
    }
}

先运营server,再开发银行client,输入参数,回车,两者第三次对话实现。

小结总计:

当下例子中大家利用了正规化io
socket,那里的诸多时候会卡住,如accept()、read()时都会阻塞。测试的时候能够让客户端睡眠几秒,在那里面运维第四个客户端,那么些时候第一个客户端未成功前,首个客户端是被堵塞在accept()中的。
 这种意况能够给种种客户端都独立分配3个线程,可是如此创建过多的线程,只怕会严重影响服务器的特性。
第三种缓解方案便是使用NIO
非阻塞的通讯格局,jdk1.4事后已经引入了这几个成效,那样能够使得服务器要是开动三个线程就能处理全体的客户端socket请求。netty就是基于NIO的高品质框架,比较jdk
nio做了众多校订,修复了一部分缺陷。  (那里不对netty与jdk
nio做过多废话,那不在大家切磋原理细节里,要是大家对那上边有趣味,作者会单独写篇小说举行深度讲解)

 

NO.2 体系化方式

在真的的项目中,很多时候我们传的都以友善定义的类。在长途通信中,类的传输我们须要对类进行种类化和反种类化。种类化的法门有多种,如二进制、xml、soap。大家就以用的最多的二进制进行举例:

socket服务端:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * socket编程之:传输对象server
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketObjectSever {

    private ServerSocket serverSocket;
    private ObjectInputStream in;
    private ObjectOutputStream out;

    public SocketObjectSever() {
        try {
            serverSocket = new ServerSocket(9999);

            while (true) {
                // 此处会阻塞,后面会讲到nio的作用
                Socket socket = serverSocket.accept();

                in = new ObjectInputStream(socket.getInputStream());
                out = new ObjectOutputStream(socket.getOutputStream());

                // 接收server端传来的数据,并转为Student
                Student student = (Student) in.readObject();
                // 重写了toString()方法,打印出来看看
                System.out.println("Server: " + student);

                // 返回给client端,通知我已收到数据
                out.writeObject("yes client, I receive");
                out.flush();

            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketObjectSever();
    }

}

 

socket客户端:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;


/**
 * socket编程之:传输对象client
 * 
 * @author chengwei.lcw 2016-11-27
 */
public class SocketObjectClient {
    private Socket socket;
    private ObjectInputStream in;
    private ObjectOutputStream out;

    public SocketObjectClient() {
        try {
            socket = new Socket("127.0.0.1",9999);
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());

            /*
             * 建一个student对象,用于传输
             */
            Student s = new Student("chengwei.lcw", 28);

            // 把对象写到管道中,client端进行接收
            out.writeObject(s);
            out.flush();

            String receive = (String) in.readObject();
            System.out.println("Client Receive :"+receive);

            in.close();
            out.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new SocketObjectClient();
    }

}

 

其它定义2个要传输的类:

import java.io.Serializable;

/**
 * socket编程之:要进行传输的类,需要继承Serializable接口
 * 
 * @author chengwei.lcw 2016-11-27
 * 
 */
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString() {
        return "name=" + this.name + ", age=" + this.age; 
    }
}

反之亦然先运营server,再起步client,server端控制台出口:

Server: name=chengwei.lcw, age=28

那般结束,大家的socket能够传输对象了。

此间我们运用的连串化情势为java直接开始展览连串化,而hessian连串化比Java系列化高效很多,生成的字节流也要短很多,因为hessian在连串化时会把字节流实行削减。在前面包车型大巴晋级版中自小编会采纳hessian体系化的法子展开种类化。

 

商厦里还有事,而且笔者不精晓那些是或不是各位朋友想看看的始末,忙完后天笔者会继续拓展补缺。
哪个地方有讲的不规则的冀望大家来校订。

 

从头开头(一),hsfdubbo 前言
阔别了很久和讯,即便看了原先写的成百上千东西感觉好天真,可是依旧认为应该把一…

背景

学过java的都施用过陆风X8MI框架(remote method
invocation),远程方法调用,比如A,B二个服务器,A调用B服务器上的法子就像调用本地点法一致,但是精神上是跨机器的调用了,A机器将调用的点子名,参数通过字节码的方式传输到B这台机械上,B那台机械将这几个字节码转换来对B机器上具体方法的调用,并将相应的重返值系列化成二进制数据传输到A服务器上。

奥迪Q3PC(Remote Procedure
Call)其实和rmi及其类似,HavalPC与奥迪Q5MI框架相比较的优势就是好多本田CR-VPC框架都以跨语言的。

奥迪Q7MI只针对java,A,B服务都采用java编写。大约拥有的奥迪Q5PC框架都存在代码生成,自动代码屏蔽了底层系列化通讯等各样细节的处理,使得用户(开发者)能够像调用本地点法一致调用长途的方法。一般那种自动生成的代码在客户端大家称为stub,服务端我们誉为skeleton。

体系化与反系列化技术,也叫做编码与解码技术,比如我们本篇博客商量的GoogleProtobuf,和marshalling等技能。

从广义上来讲,webservice也足以称之为RAV4PC框架,不过比较于别的的OdysseyPC框架来说,webservice的习性稍微差一点,因为决定三个rpc品质的绝妙与否在于其底层对象编解码品质。LacrossePC一般皆以依照socket协议传输的,而webservice基于http传输的,socket协议的品质也要高于http协议传输数据。所以,一般在小卖部内部各样微服务之间的劳动调用都使用凯雷德PC框架多或多或少,因为在质量上的考虑,而作者辈总所周知的dubbo纵然也毕竟凯雷德PC框架,但骨子里并不匡助多语言。

为何要写这几个PAJEROPC

市面上常见的帕杰罗PC框架很多,grpc,motan,dubbo等,但是随着越多的成分参加,复杂的架构划设想计等因素似使得那么些框架就想spring一样,尽管称之为是轻量级,可是用起来却是让大家很不佳,大批量的安排,繁杂的API设计,其实,我们平素用不上那几个事物!!!
小编也算得上是在重重个互连网公司厮杀过,见过不少广大的当中HavalPC框架,有些优异的筹划让自家丰裕赞扬,有一天作者猛然想着,为啥不对那一个安排原型举办联谊归类,本身搞一套本田CR-VPC框架呢,碍于工作原因,一向没有时间倒腾出空,十一中间工作闲暇,说搞就搞吧,希望源码对我们对认识RPC框架起到推进的作用。东西越写越来越多,有各类题材欢迎随时拍砖

帕杰罗PC基础概念

GL450PC正是长途进度调用协议,其功能正是客户端与服务端之间的长途调用,就像是当地本人调用一样,让服务端进行服务化,效用唯一性,负载热点流量。

种类化与反种类化

  类别化与反种类化这些选二进制一般比json的好,ms版的BinaryFormatter
通用性强,不过她的属性、model的标记写法等估量又要被喷了;找到Expression系列化,结果或然走的切近于soap
xml这一套,想想算了:本地点法调用都以微秒级的,io皆以飞秒级别的,socket的2回就传这么传这么大学一年级堆,即便局域网也伤不起呀,想轻量化升高质量都难,自行达成三个简便的好了。

  1 /****************************************************************************
  2 *Copyright (c) 2018 Microsoft All Rights Reserved.
  3 *CLR版本: 4.0.30319.42000
  4 *机器名称:WENLI-PC
  5 *公司名称:Microsoft
  6 *命名空间:SAEA.RPC.Serialize
  7 *文件名: SerializeUtil
  8 *版本号: V1.0.0.0
  9 *唯一标识:9e919430-465d-49a3-91be-b36ac682e283
 10 *当前的用户域:WENLI-PC
 11 *创建人: yswenli
 12 *电子邮箱:wenguoli_520@qq.com
 13 *创建时间:2018/5/22 13:17:36
 14 *描述:
 15 *
 16 *=====================================================================
 17 *修改标记
 18 *修改时间:2018/5/22 13:17:36
 19 *修改人: yswenli
 20 *版本号: V1.0.0.0
 21 *描述:
 22 *
 23 *****************************************************************************/
 24 using SAEA.RPC.Model;
 25 using System;
 26 using System.Collections.Generic;
 27 using System.Text;
 28 
 29 namespace SAEA.RPC.Serialize
 30 {
 31     /// <summary>
 32     /// rpc参数序列化处理
 33     /// </summary>
 34     public class ParamsSerializeUtil
 35     {
 36         /// <summary>
 37         /// len+data
 38         /// </summary>
 39         /// <param name="param"></param>
 40         /// <returns></returns>
 41         public static byte[] Serialize(object param)
 42         {
 43             List<byte> datas = new List<byte>();
 44 
 45             var len = 0;
 46             byte[] data = null;
 47 
 48             if (param == null)
 49             {
 50                 len = 0;
 51             }
 52             else
 53             {
 54                 if (param is string)
 55                 {
 56                     data = Encoding.UTF8.GetBytes((string)param);
 57                 }
 58                 else if (param is byte)
 59                 {
 60                     data = new byte[] { (byte)param };
 61                 }
 62                 else if (param is bool)
 63                 {
 64                     data = BitConverter.GetBytes((bool)param);
 65                 }
 66                 else if (param is short)
 67                 {
 68                     data = BitConverter.GetBytes((short)param);
 69                 }
 70                 else if (param is int)
 71                 {
 72                     data = BitConverter.GetBytes((int)param);
 73                 }
 74                 else if (param is long)
 75                 {
 76                     data = BitConverter.GetBytes((long)param);
 77                 }
 78                 else if (param is float)
 79                 {
 80                     data = BitConverter.GetBytes((float)param);
 81                 }
 82                 else if (param is double)
 83                 {
 84                     data = BitConverter.GetBytes((double)param);
 85                 }
 86                 else if (param is DateTime)
 87                 {
 88                     var str = "wl" + ((DateTime)param).Ticks;
 89                     data = Encoding.UTF8.GetBytes(str);
 90                 }
 91                 else if (param is byte[])
 92                 {
 93                     data = (byte[])param;
 94                 }
 95                 else
 96                 {
 97                     var type = param.GetType();
 98 
 99                     if (type.IsGenericType || type.IsArray)
100                     {
101                         data = SerializeList((System.Collections.IEnumerable)param);
102                     }
103                     else if (type.IsGenericTypeDefinition)
104                     {
105                         data = SerializeDic((System.Collections.IDictionary)param);
106                     }
107                     else if (type.IsClass)
108                     {
109                         var ps = type.GetProperties();
110 
111                         if (ps != null && ps.Length > 0)
112                         {
113                             List<object> clist = new List<object>();
114 
115                             foreach (var p in ps)
116                             {
117                                 clist.Add(p.GetValue(param));
118                             }
119                             data = Serialize(clist.ToArray());
120                         }
121                     }
122                 }
123                 len = data.Length;
124             }
125             datas.AddRange(BitConverter.GetBytes(len));
126             if (len > 0)
127             {
128                 datas.AddRange(data);
129             }
130             return datas.Count == 0 ? null : datas.ToArray();
131         }
132 
133 
134         private static byte[] SerializeList(System.Collections.IEnumerable param)
135         {
136             List<byte> list = new List<byte>();
137 
138             if (param != null)
139             {
140                 List<byte> slist = new List<byte>();
141 
142                 foreach (var item in param)
143                 {
144                     var type = item.GetType();
145 
146                     var ps = type.GetProperties();
147                     if (ps != null && ps.Length > 0)
148                     {
149                         List<object> clist = new List<object>();
150                         foreach (var p in ps)
151                         {
152                             clist.Add(p.GetValue(item));
153                         }
154 
155                         var clen = 0;
156 
157                         var cdata = Serialize(clist.ToArray());
158 
159                         if (cdata != null)
160                         {
161                             clen = cdata.Length;
162                         }
163 
164                         slist.AddRange(BitConverter.GetBytes(clen));
165                         slist.AddRange(cdata);
166                     }
167                 }
168 
169                 var len = 0;
170 
171                 if (slist.Count > 0)
172                 {
173                     len = slist.Count;
174                 }
175                 list.AddRange(BitConverter.GetBytes(len));
176                 list.AddRange(slist.ToArray());
177             }
178             return list.ToArray();
179         }
180 
181         private static byte[] SerializeDic(System.Collections.IDictionary param)
182         {
183             List<byte> list = new List<byte>();
184 
185             if (param != null && param.Count > 0)
186             {
187                 foreach (KeyValuePair item in param)
188                 {
189                     var type = item.GetType();
190                     var ps = type.GetProperties();
191                     if (ps != null && ps.Length > 0)
192                     {
193                         List<object> clist = new List<object>();
194                         foreach (var p in ps)
195                         {
196                             clist.Add(p.GetValue(item));
197                         }
198                         var clen = 0;
199 
200                         var cdata = Serialize(clist.ToArray());
201 
202                         if (cdata != null)
203                         {
204                             clen = cdata.Length;
205                         }
206 
207                         list.AddRange(BitConverter.GetBytes(clen));
208                         list.AddRange(cdata);
209                     }
210                 }
211             }
212             return list.ToArray();
213         }
214 
215         /// <summary>
216         /// len+data
217         /// </summary>
218         /// <param name="params"></param>
219         /// <returns></returns>
220         public static byte[] Serialize(params object[] @params)
221         {
222             List<byte> datas = new List<byte>();
223 
224             if (@params != null)
225             {
226                 foreach (var param in @params)
227                 {
228                     datas.AddRange(Serialize(param));
229                 }
230             }
231 
232             return datas.Count == 0 ? null : datas.ToArray();
233         }
234 
235         /// <summary>
236         /// 反序列化
237         /// </summary>
238         /// <param name="types"></param>
239         /// <param name="datas"></param>
240         /// <returns></returns>
241         public static object[] Deserialize(Type[] types, byte[] datas)
242         {
243             List<object> list = new List<object>();
244 
245             var len = 0;
246 
247             byte[] data = null;
248 
249             int offset = 0;
250 
251             for (int i = 0; i < types.Length; i++)
252             {
253                 list.Add(Deserialize(types[i], datas, ref offset));
254             }
255 
256             return list.ToArray();
257         }
258 
259         /// <summary>
260         /// 反序列化
261         /// </summary>
262         /// <param name="type"></param>
263         /// <param name="datas"></param>
264         /// <param name="offset"></param>
265         /// <returns></returns>
266         public static object Deserialize(Type type, byte[] datas, ref int offset)
267         {
268             dynamic obj = null;
269 
270             var len = 0;
271 
272             byte[] data = null;
273 
274             len = BitConverter.ToInt32(datas, offset);
275             offset += 4;
276             if (len > 0)
277             {
278                 data = new byte[len];
279                 Buffer.BlockCopy(datas, offset, data, 0, len);
280                 offset += len;
281 
282                 if (type == typeof(string))
283                 {
284                     obj = Encoding.UTF8.GetString(data);
285                 }
286                 else if (type == typeof(byte))
287                 {
288                     obj = (data);
289                 }
290                 else if (type == typeof(bool))
291                 {
292                     obj = (BitConverter.ToBoolean(data, 0));
293                 }
294                 else if (type == typeof(short))
295                 {
296                     obj = (BitConverter.ToInt16(data, 0));
297                 }
298                 else if (type == typeof(int))
299                 {
300                     obj = (BitConverter.ToInt32(data, 0));
301                 }
302                 else if (type == typeof(long))
303                 {
304                     obj = (BitConverter.ToInt64(data, 0));
305                 }
306                 else if (type == typeof(float))
307                 {
308                     obj = (BitConverter.ToSingle(data, 0));
309                 }
310                 else if (type == typeof(double))
311                 {
312                     obj = (BitConverter.ToDouble(data, 0));
313                 }
314                 else if (type == typeof(decimal))
315                 {
316                     obj = (BitConverter.ToDouble(data, 0));
317                 }
318                 else if (type == typeof(DateTime))
319                 {
320                     var dstr = Encoding.UTF8.GetString(data);
321                     var ticks = long.Parse(dstr.Substring(2));
322                     obj = (new DateTime(ticks));
323                 }
324                 else if (type == typeof(byte[]))
325                 {
326                     obj = (byte[])data;
327                 }
328                 else if (type.IsGenericType)
329                 {
330                     obj = DeserializeList(type, data);
331                 }
332                 else if (type.IsArray)
333                 {
334                     obj = DeserializeArray(type, data);
335                 }
336                 else if (type.IsGenericTypeDefinition)
337                 {
338                     obj = DeserializeDic(type, data);
339                 }
340                 else if (type.IsClass)
341                 {
342                     var instance = Activator.CreateInstance(type);
343 
344                     var ts = new List<Type>();
345 
346                     var ps = type.GetProperties();
347 
348                     if (ps != null)
349                     {
350                         foreach (var p in ps)
351                         {
352                             ts.Add(p.PropertyType);
353                         }
354                         var vas = Deserialize(ts.ToArray(), data);
355 
356                         for (int j = 0; j < ps.Length; j++)
357                         {
358                             try
359                             {
360                                 if (!ps[j].PropertyType.IsGenericType)
361                                 {
362                                     ps[j].SetValue(instance, Convert.ChangeType(vas[j], ps[j].PropertyType), null);
363                                 }
364                                 else
365                                 {
366                                     Type genericTypeDefinition = ps[j].PropertyType.GetGenericTypeDefinition();
367                                     if (genericTypeDefinition == typeof(Nullable<>))
368                                     {
369                                         ps[j].SetValue(instance, Convert.ChangeType(vas[j], Nullable.GetUnderlyingType(ps[j].PropertyType)), null);
370                                     }
371                                     else
372                                     {
373                                         //List<T>问题
374                                         ps[j].SetValue(instance, Convert.ChangeType(vas[j], ps[j].PropertyType), null);
375                                     }
376                                 }
377                             }
378                             catch (Exception ex)
379                             {
380                                 Console.WriteLine("反序列化不支持的类型:" + ex.Message);
381                             }
382                         }
383                     }
384                     obj = (instance);
385                 }
386                 else
387                 {
388                     throw new RPCPamarsException("ParamsSerializeUtil.Deserialize 未定义的类型:" + type.ToString());
389                 }
390 
391             }
392             return obj;
393         }
394 
395 
396         private static object DeserializeList(Type type, byte[] datas)
397         {
398             List<object> result = new List<object>();
399             var stype = type.GenericTypeArguments[0];
400 
401             var len = 0;
402             var offset = 0;
403             //容器大小
404             len = BitConverter.ToInt32(datas, offset);
405             offset += 4;
406             byte[] cdata = new byte[len];
407             Buffer.BlockCopy(datas, offset, cdata, 0, len);
408             offset += len;
409 
410             //子项内容
411             var slen = 0;
412             var soffset = 0;
413             while (soffset < len)
414             {
415                 slen = BitConverter.ToInt32(cdata, soffset);
416                 var sdata = new byte[slen + 4];
417                 Buffer.BlockCopy(cdata, soffset, sdata, 0, slen + 4);
418                 soffset += slen + 4;
419 
420                 if (slen > 0)
421                 {
422                     int lloffset = 0;
423                     var sobj = Deserialize(stype, sdata, ref lloffset);
424                     if (sobj != null)
425                         result.Add(sobj);
426                 }
427                 else
428                 {
429                     result.Add(null);
430                 }
431             }
432             return result;
433         }
434 
435         private static object DeserializeArray(Type type, byte[] datas)
436         {
437             var obj = DeserializeList(type, datas);
438 
439             if (obj == null) return null;
440 
441             var list = (obj as List<object>);
442 
443             return list.ToArray();
444         }
445 
446         private static object DeserializeDic(Type type, byte[] datas)
447         {
448             dynamic obj = null;
449 
450 
451 
452             return obj;
453         }
454     }
455 }

  完结的长河中,一般结构、类都还比较顺遂,然则数组、List、Dictionary照旧碰着了某个难为,近来先放着,找到方法加以。真尽管传那几个,近年来先用其余体系化成byte[]来做……

什么是protocol buffers?

Protocol
buffers是谷歌(Google)的言语中立,平纽伦堡立的,可扩张机制的连串化数据结构框架-能够用作是xml,不过体积更小,传输速率更快,使用更为简约。一旦你定义了你的多少格式,你能够应用生李松益代码去轻松地从各类数据流读和写你的结构化数据同时使用区别的言语。protobuf有2.0本子和3.0本子,3.0版本十grpc框架的根基

Protocol buffers最近帮忙Java, Python, Objective-C,
和C++生成代码。新的proto3语言版本,你能够利用Go, JavaNano, Ruby, 和
C#。

ENCOREPC框架的兑现

LacrossePC能够让地点使用简单、高效地调用服务器中的进度。它根本运用在分布式系统。如Hadoop中的IPC组件。但怎么样完成一个LANDPC框架呢?

从下边多少个地点考虑,仅供参考:

1.通讯模型:即使通讯的为A机器与B机器,A与B之间有通讯模型,在Java中一般基于BIO或NIO;。

2.进度定位:使用给定的通讯情势,与规定IP与端口及措施名称明确具体的历程或格局;

3.远程代理对象:本地调用的方法其实是长途方法的地面代理,由此可能须求三个长距离代理对象,对于Java而言,远程代理对象能够动用Java的动态目的达成,封装了调用远程方法调用;

4.连串化,将指标名称、方法名称、参数等对象消息实行网络传输必要转换到二进制传输,那里恐怕供给不一致的体系化技术方案。如:thrift,protobuf,Arvo等。

上边用简易的原生java socket来贯彻rpc调用,方便大家更深层明白rpc原理

服务类接口

1 package socketrpc;2 3 public interface IHello {4      String sayHello(String string);5 }

劳动实现类

 1 package socketrpc.server; 2  3 import socketrpc.IHello; 4  5 public class HelloServiceImpl implements IHello { 6  7     @Override 8     public String sayHello(String string) { 9         return "你好:".concat ;10     }11 }

客户端实现

package socketrpc.client;import socketrpc.IHello;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.net.InetSocketAddress;import java.net.Socket;public class RpcClientProxy<T> implements InvocationHandler {    private  Class<T> serviceInterface;    private InetSocketAddress addr;    public RpcClientProxy(Class<T> serviceInterface, String ip,String port) {        this.serviceInterface = serviceInterface;        this.addr = new InetSocketAddress(ip, Integer.parseInt ;    }    public T getClientIntance(){        return  Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this);    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        Socket socket = null;        ObjectOutputStream output = null;        ObjectInputStream input = null;        try {            // 2.创建Socket客户端,根据指定地址连接远程服务提供者            socket = new Socket();            socket.connect;            // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者            output = new ObjectOutputStream(socket.getOutputStream;            output.writeUTF(serviceInterface.getName;            output.writeUTF(method.getName;            output.writeObject(method.getParameterTypes;            output.writeObject;            // 4.同步阻塞等待服务器返回应答,获取应答后返回            input = new ObjectInputStream(socket.getInputStream;            return input.readObject();        } finally {            if (socket != null) socket.close();            if (output != null) output.close();            if (input != null) input.close();        }    }    public static void main(String[] args) {        RpcClientProxy client = new RpcClientProxy<>(IHello.class,"localhost","6666");        IHello hello =  client.getClientIntance ();        System.out.println (hello.sayHello ( "socket rpc" ));    }}

服务端完毕

package socketrpc.server;import socketrpc.IHello;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Method;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;public class RpcServer {    private static final HashMap<String, Class<?>> serviceRegistry = new HashMap<>();    private  int port;    public RpcServer(int port) {        this.port =port;    }    public RpcServer register(Class serviceInterface, Class impl) {        serviceRegistry.put(serviceInterface.getName;        return this;    }    public void run() throws IOException {        ServerSocket server = new ServerSocket();        server.bind(new InetSocketAddress ;        System.out.println("start server");        ObjectInputStream input =null;        ObjectOutputStream output =null;        Socket socket=null;        try {            while(true){                socket = server.accept ();                input =new ObjectInputStream(socket.getInputStream;                String serviceName = input.readUTF();                String methodName = input.readUTF();                System.out.println (methodName);                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();                Object[] arguments =  input.readObject();                Class serviceClass = serviceRegistry.get(serviceName);                if (serviceClass == null) {                    throw new ClassNotFoundException(serviceName + " not found");                }                Method method = serviceClass.getMethod(methodName, parameterTypes);                Object result = method.invoke(serviceClass.newInstance(), arguments);                output = new ObjectOutputStream (socket.getOutputStream;                output.writeObject;            }        } catch (Exception e){            e.printStackTrace();        }finally {            if (output != null) {                try {                    output.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (input != null) {                try {                    input.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (socket != null) {                try {                    socket.close();                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) throws IOException {        new RpcServer .register ( IHello.class,HelloServiceImpl.class).run ();    }}

开行服务端和客户端后运营结果如下

澳门葡京备用网址 1

澳门葡京备用网址 2

客户端代码不难讲解

 1  private  Class<T> serviceInterface; 2     private InetSocketAddress addr; 3  4     public RpcClientProxy(Class<T> serviceInterface, String ip,String port) { 5         this.serviceInterface = serviceInterface; 6         this.addr = new InetSocketAddress(ip, Integer.parseInt ; 7     } 8  9     public T getClientIntance(){10         return  Proxy.newProxyInstance (serviceInterface.getClassLoader(),new Class<?>[]{serviceInterface},this);11     }

盛传接口类和ip端口,调用getClientIntance方法时,对近来接口举行代理,实际调用方法为

 1 @Override 2     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 3  4         Socket socket = null; 5         ObjectOutputStream output = null; 6         ObjectInputStream input = null; 7  8         try { 9             // 2.创建Socket客户端,根据指定地址连接远程服务提供者10             socket = new Socket();11             socket.connect;12 13             // 3.将远程服务调用所需的接口类、方法名、参数列表等编码后发送给服务提供者14             output = new ObjectOutputStream(socket.getOutputStream;15             output.writeUTF(serviceInterface.getName;16             output.writeUTF(method.getName;17             output.writeObject(method.getParameterTypes;18             output.writeObject;19 20             // 4.同步阻塞等待服务器返回应答,获取应答后返回21             input = new ObjectInputStream(socket.getInputStream;22             return input.readObject();23         } finally {24             if (socket != null) socket.close();25             if (output != null) output.close();26             if (input != null) input.close();27         }28     }

服从上面步骤

1:创造socket,并和远程举办一次接二连三握手【socket.connect。

2:封装socket输出流【ObjectOutputStream】。

3:输出类名称,方法名称,参数类型和参数值给server。

4:获取socket输入流,等待server再次来到结果。

服务端代码不难讲解

1 public RpcServer(int port) {2         this.port =port;3     }4 5     public RpcServer register(Class serviceInterface, Class impl) {6         serviceRegistry.put(serviceInterface.getName;7         return this;8     }

开头化服务端,将服务类注册到hashMap【模拟spring上下文】

 1 public void run() throws IOException { 2  3         ServerSocket server = new ServerSocket(); 4         server.bind(new InetSocketAddress ; 5         System.out.println("start server"); 6         ObjectInputStream input =null; 7         ObjectOutputStream output =null; 8         Socket socket=null; 9         try {10             while(true){11                 socket = server.accept ();12                 input =new ObjectInputStream(socket.getInputStream;13 14                 String serviceName = input.readUTF();15                 String methodName = input.readUTF();16                 System.out.println (methodName);17                 Class<?>[] parameterTypes = (Class<?>[]) input.readObject();18                 Object[] arguments =  input.readObject();19                 Class serviceClass = serviceRegistry.get(serviceName);20                 if (serviceClass == null) {21                     throw new ClassNotFoundException(serviceName + " not found");22                 }23                 Method method = serviceClass.getMethod(methodName, parameterTypes);24                 Object result = method.invoke(serviceClass.newInstance(), arguments);25                 output = new ObjectOutputStream (socket.getOutputStream;26                 output.writeObject;27             }28         } catch (Exception e){29             e.printStackTrace();30         }finally {31             if (output != null) {32                 try {33                     output.close();34                 } catch (IOException e) {35                     e.printStackTrace();36                 }37             }38             if (input != null) {39                 try {40                     input.close();41                 } catch (IOException e) {42                     e.printStackTrace();43                 }44             }45             if (socket != null) {46                 try {47                     socket.close();48                 } catch (IOException e) {49                     e.printStackTrace();50                 }51             }52         }53 54     }

服务端执行做了以下几件事:

1:绑定端口,阻塞等待客户端调用【socket = server.accept 。

2:封装输入流【socket.getInputStream。

3:从输入流中获取到接口名,方法名,参数类型,参数值。

4:找到伊始化时hashmap中的服务类。

5:反射获取服务实现类措施并基于请求参数进行服务调用。

6:封装输出流【ObjectOutputStream】,并且重回结果。

到近来截至,整个大致的socket实现的ENCOREPC服务就已经全部到位了,能够优化的一对。

1:类别化局限,原生系列化只好系列化完成了【塞里alizable】接口的服务类,并且序列化复杂对象时,内容庞大功能相当低,需求快捷的系列化协议实行体系化参数方法等必备请求入参

2:BIO质量局限,socket服务端采纳暗许的BIO来阻塞获取输入流,功能低下,需接纳NIO等异步非阻塞服务端方案,例如netty,mina和java
nio等。

3:在巨型商厦级TiguanPC消除方案中,客户端和服务端的长连接要求向来维系,不然每回调用时都要重复进行2遍握手和六次挥手,那样往往的开创tcp连接对机械质量是十分的大的损耗,对socket的再而三能够行使apache
pool2连接池等方案

4:服务端负载,须要考虑服务活动发现,让客户端在不须要重启的动静下能动态感知服务端的成形,从而完毕热安排等。能够行使方法定时自动轮询,zookeeper等。

5:服务端服务类执行分外,客户端感知等。

好了,相信看完本章内容对于rpc框架来说,我们早就将基础通晓的大都了,上面笔者将会给大家无微不至授课基于zk,thrift,netty的商户级福特ExplorerPC化解方案

远程方法反转

  远程方法反转就是将收到到的数码一定到地头的对象方法上,假使代码生成、参数使用应用泛型反连串化,理论上是能够升官部分属性的;不过另一方面写服务业务,一边编写定义结构文件、还一边生成服务代码,本地方法都以皮秒级、相对io的进程来讲,借使为了那点质量进步,在动用的时候测度又是一阵@##¥%*#¥@#&##@……,所以依旧接纳反射、拆箱吧。

  1 /****************************************************************************
  2 *Copyright (c) 2018 Microsoft All Rights Reserved.
  3 *CLR版本: 4.0.30319.42000
  4 *机器名称:WENLI-PC
  5 *公司名称:Microsoft
  6 *命名空间:SAEA.RPC.Common
  7 *文件名: RPCInovker
  8 *版本号: V1.0.0.0
  9 *唯一标识:289c03b9-3910-4e15-8072-93243507689c
 10 *当前的用户域:WENLI-PC
 11 *创建人: yswenli
 12 *电子邮箱:wenguoli_520@qq.com
 13 *创建时间:2018/5/17 14:11:30
 14 *描述:
 15 *
 16 *=====================================================================
 17 *修改标记
 18 *修改时间:2018/5/17 14:11:30
 19 *修改人: yswenli
 20 *版本号: V1.0.0.0
 21 *描述:
 22 *
 23 *****************************************************************************/
 24 using SAEA.RPC.Model;
 25 using SAEA.RPC.Net;
 26 using SAEA.RPC.Serialize;
 27 using SAEA.Sockets.Interface;
 28 using System;
 29 using System.Linq;
 30 using System.Reflection;
 31 
 32 namespace SAEA.RPC.Common
 33 {
 34     /// <summary>
 35     /// RPC将远程调用反转到本地服务
 36     /// </summary>
 37     public class RPCReversal
 38     {
 39         static object _locker = new object();
 40         
 41 
 42         /// <summary>
 43         /// 执行方法
 44         /// </summary>
 45         /// <param name="action"></param>
 46         /// <param name="obj"></param>
 47         /// <param name="args"></param>
 48         /// <returns></returns>
 49         private static object ReversalMethod(MethodInfo action, object obj, object[] args)
 50         {
 51             object result = null;
 52             try
 53             {
 54                 var @params = action.GetParameters();
 55 
 56                 if (@params != null && @params.Length > 0)
 57                 {
 58                     result = action.Invoke(obj, args);
 59                 }
 60                 else
 61                 {
 62                     result = action.Invoke(obj, null);
 63                 }
 64             }
 65             catch (Exception ex)
 66             {
 67                 throw new RPCPamarsException($"{obj}/{action.Name},出现异常:{ex.Message}", ex);
 68             }
 69             return result;
 70         }
 71 
 72 
 73         public static object Reversal(IUserToken userToken, string serviceName, string methodName, object[] inputs)
 74         {
 75             lock (_locker)
 76             {
 77                 try
 78                 {
 79                     var serviceInfo = RPCMapping.Get(serviceName, methodName);
 80 
 81                     if (serviceInfo == null)
 82                     {
 83                         throw new RPCNotFundException($"当前请求找不到:{serviceName}/{methodName}", null);
 84                     }
 85 
 86                     var nargs = new object[] { userToken, serviceName, methodName, inputs };
 87 
 88                     if (serviceInfo.FilterAtrrs != null && serviceInfo.FilterAtrrs.Count > 0)
 89                     {
 90                         foreach (var arr in serviceInfo.FilterAtrrs)
 91                         {
 92                             var goOn = (bool)arr.GetType().GetMethod("OnActionExecuting").Invoke(arr, nargs.ToArray());
 93 
 94                             if (!goOn)
 95                             {
 96                                 return new RPCNotFundException("当前逻辑已被拦截!", null);
 97                             }
 98                         }
 99                     }
100 
101                     if (serviceInfo.ActionFilterAtrrs != null && serviceInfo.ActionFilterAtrrs.Count > 0)
102                     {
103                         foreach (var arr in serviceInfo.ActionFilterAtrrs)
104                         {
105                             var goOn = (bool)arr.GetType().GetMethod("OnActionExecuting").Invoke(arr, nargs.ToArray());
106 
107                             if (!goOn)
108                             {
109                                 return new RPCNotFundException("当前逻辑已被拦截!", null);
110                             }
111                         }
112                     }
113 
114                     var result = ReversalMethod(serviceInfo.Mothd, serviceInfo.Instance, inputs);
115 
116                     nargs = new object[] { userToken, serviceName, methodName, inputs, result };
117 
118                     if (serviceInfo.FilterAtrrs != null && serviceInfo.FilterAtrrs.Count > 0)
119                     {
120                         foreach (var arr in serviceInfo.FilterAtrrs)
121                         {
122                             arr.GetType().GetMethod("OnActionExecuted").Invoke(arr, nargs);
123                         }
124                     }
125 
126                     if (serviceInfo.ActionFilterAtrrs != null && serviceInfo.ActionFilterAtrrs.Count > 0)
127                     {
128                         foreach (var arr in serviceInfo.FilterAtrrs)
129                         {
130                             arr.GetType().GetMethod("OnActionExecuted").Invoke(arr, nargs);
131                         }
132                     }
133                     return result;
134                 }
135                 catch (Exception ex)
136                 {
137                     if (ex.Message.Contains("找不到此rpc方法"))
138                     {
139                         return new RPCNotFundException("找不到此rpc方法", ex);
140                     }
141                     else
142                     {
143                         return new RPCNotFundException("找不到此rpc方法", ex);
144                     }
145                 }
146             }
147         }
148 
149         /// <summary>
150         /// 反转到具体的方法上
151         /// </summary>
152         /// <param name="userToken"></param>
153         /// <param name="msg"></param>
154         /// <returns></returns>
155         public static byte[] Reversal(IUserToken userToken, RSocketMsg msg)
156         {
157             byte[] result = null;
158             try
159             {
160                 object[] inputs = null;
161 
162                 if (msg.Data != null)
163                 {
164                     var ptypes = RPCMapping.Get(msg.ServiceName, msg.MethodName).Pamars.Values.ToArray();
165 
166                     inputs = ParamsSerializeUtil.Deserialize(ptypes, msg.Data);
167                 }
168 
169                 var r = Reversal(userToken, msg.ServiceName, msg.MethodName, inputs);
170 
171                 if (r != null)
172                 {
173                     return ParamsSerializeUtil.Serialize(r);
174                 }
175             }
176             catch (Exception ex)
177             {
178                 throw new RPCPamarsException("RPCInovker.Invoke error:" + ex.Message, ex);
179             }
180             return result;
181 
182         }
183     }
184 }

为啥使用Protocol buffers

选取二个简单易行的可以从二个文书中去读写职员关系新闻”地址簿”程序。各个在地址簿的人有真名,id,邮箱地址和1个联络员电话号码属性。

您如何连串化和摸索那样的结构化数据? 有二种艺术来解决那些标题:
利用java原生的连串化。那是一种默许的法子因为是内嵌于java语言的,但是有一大堆远近出名的标题(参考Effective
Java那本书),并且你不可能将数据分享于C++和Python应用(也正是不可能跨语言)。

还能将数据项编码为单个字符串的ad-hoc方式 –
例如将6个ints编码为“12:3:-23:67”。
那是二个简短而灵活的法子,尽管它须求编写制定一回性编码和剖析代码,并且解析具有相当的小的运维时资金。
那最契合编码卓殊不难的数目。

将数据类别化为XML。
那种措施恐怕万分有吸重力,因为XML是(大概的)人类可读的,并且有无数言语的绑定库。
假若你想与任何应用程序/项目共享数据,那大概是一个很好的精选。
但是,XML浪费品质,编码/解码可能会对应用程序造成巨大的性情损失。
其它,检索XML DOM树比在相似类中不难的字段检索要复杂得多。

Protocol buffers是灵活,高效,自动化的消除方案来消除这几个难题。
使用Protocol buffers,您能够编写2个.proto描述您愿意存储的数据结构。
Protocol
buffers编写翻译器创制3个达成自动编码和分析协议缓冲区数据的类,并应用高效的二进制格式。
生成的类为组合Protocol buffers的字段提供getter和setter。

客户端代码生成

  为了便利客户使用rpc,所以有rpc相关的代码在客户端那必将是越少越好,借使光服务端方便,客户端推测又要@##¥%*#¥@#&##@……,所以将有个别rpc相关代码生成好,客户端透明调用是必须的。

  1 /****************************************************************************
  2 *Copyright (c) 2018 Microsoft All Rights Reserved.
  3 *CLR版本: 4.0.30319.42000
  4 *机器名称:WENLI-PC
  5 *公司名称:Microsoft
  6 *命名空间:SAEA.RPC.Generater
  7 *文件名: CodeGnerater
  8 *版本号: V1.0.0.0
  9 *唯一标识:59ba5e2a-2fd0-444b-a260-ab68c726d7ee
 10 *当前的用户域:WENLI-PC
 11 *创建人: yswenli
 12 *电子邮箱:wenguoli_520@qq.com
 13 *创建时间:2018/5/17 18:30:57
 14 *描述:
 15 *
 16 *=====================================================================
 17 *修改标记
 18 *修改时间:2018/5/17 18:30:57
 19 *修改人: yswenli
 20 *版本号: V1.0.0.0
 21 *描述:
 22 *
 23 *****************************************************************************/
 24 using SAEA.RPC.Common;
 25 using SAEA.RPC.Model;
 26 using System;
 27 using System.Collections.Generic;
 28 using System.IO;
 29 using System.Linq;
 30 using System.Reflection;
 31 using System.Text;
 32 
 33 namespace SAEA.RPC.Generater
 34 {
 35     /// <summary>
 36     /// 代码生成器
 37     /// </summary>
 38     public static class CodeGnerater
 39     {
 40         static string space4 = "    ";
 41 
 42         /// <summary>
 43         /// 获取指定数量的空格
 44         /// </summary>
 45         /// <param name="num"></param>
 46         /// <returns></returns>
 47         static string GetSpace(int num = 1)
 48         {
 49             var sb = new StringBuilder();
 50 
 51             for (int i = 0; i < num; i++)
 52             {
 53                 sb.Append(space4);
 54             }
 55 
 56             return sb.ToString();
 57         }
 58 
 59         /// <summary>
 60         /// 获取变量名
 61         /// </summary>
 62         /// <param name="str"></param>
 63         /// <returns></returns>
 64         static string GetSuffixStr(string str)
 65         {
 66             return "_" + str.Substring(0, 1).ToLower() + str.Substring(1);
 67         }
 68 
 69         /// <summary>
 70         /// 生成代码头部
 71         /// </summary>
 72         /// <returns></returns>
 73         static string Header(params string[] usings)
 74         {
 75             var sb = new StringBuilder();
 76             sb.AppendLine("/*******");
 77             sb.AppendLine($"*此代码为SAEA.RPCGenerater生成 {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
 78             sb.AppendLine("*******/" + Environment.NewLine);
 79             sb.AppendLine("using System;");
 80             if (usings != null)
 81             {
 82                 foreach (var u in usings)
 83                 {
 84                     sb.AppendLine(u);
 85                 }
 86             }
 87             return sb.ToString();
 88         }
 89 
 90         static string _proxyStr;
 91 
 92         static List<string> _serviceStrs = new List<string>();
 93 
 94         static Dictionary<string, string> _modelStrs = new Dictionary<string, string>();
 95 
 96         /// <summary>
 97         /// 生成代理代码
 98         /// </summary>
 99         /// <param name="spaceName"></param>
100         internal static void GenerateProxy(string spaceName)
101         {
102             StringBuilder csStr = new StringBuilder();
103             csStr.AppendLine(Header("using SAEA.RPC.Consumer;", $"using {spaceName}.Consumer.Model;", $"using {spaceName}.Consumer.Service;"));
104             csStr.AppendLine($"namespace {spaceName}.Consumer");
105             csStr.AppendLine("{");
106             csStr.AppendLine($"{GetSpace(1)}public class RPCServiceProxy");
107             csStr.AppendLine(GetSpace(1) + "{");
108 
109             csStr.AppendLine(GetSpace(2) + "ServiceConsumer _serviceConsumer;");
110             csStr.AppendLine(GetSpace(2) + "public RPCServiceProxy(string uri = \"rpc://127.0.0.1:39654\") : this(new Uri(uri)){}");
111             csStr.AppendLine(GetSpace(2) + "public RPCServiceProxy(Uri uri)");
112             csStr.AppendLine(GetSpace(2) + "{");
113 
114             csStr.AppendLine(GetSpace(3) + "_serviceConsumer = new ServiceConsumer(uri);");
115 
116             var names = RPCMapping.GetServiceNames();
117 
118             if (names != null)
119             {
120                 foreach (var name in names)
121                 {
122                     csStr.AppendLine(GetSpace(3) + GetSuffixStr(name) + $" = new {name}(_serviceConsumer);");
123                 }
124             }
125             csStr.AppendLine(GetSpace(2) + "}");
126 
127             if (names != null)
128             {
129                 foreach (var name in names)
130                 {
131                     var suffixStr = GetSuffixStr(name);
132 
133                     csStr.AppendLine(GetSpace(2) + $"{name} {suffixStr};");
134                     csStr.AppendLine(GetSpace(2) + $"public {name} {name}");
135                     csStr.AppendLine(GetSpace(2) + "{");
136                     csStr.AppendLine($"{GetSpace(3)} get{{ return {suffixStr}; }}");
137                     csStr.AppendLine(GetSpace(2) + "}");
138 
139                     var list = RPCMapping.GetAll(name);
140                     if (list != null)
141                     {
142                         GenerateService(spaceName, name, list);
143                     }
144                 }
145             }
146 
147             csStr.AppendLine(GetSpace(1) + "}");
148             csStr.AppendLine("}");
149             _proxyStr = csStr.ToString();
150         }
151         /// <summary>
152         /// 生成调用服务代码
153         /// </summary>
154         /// <param name="spaceName"></param>
155         /// <param name="serviceName"></param>
156         /// <param name="methods"></param>
157         internal static void GenerateService(string spaceName, string serviceName, Dictionary<string, ServiceInfo> methods)
158         {
159             StringBuilder csStr = new StringBuilder();
160             csStr.AppendLine($"namespace {spaceName}.Consumer.Service");
161             csStr.AppendLine("{");
162             csStr.AppendLine($"{GetSpace(1)}public class {serviceName}");
163             csStr.AppendLine(GetSpace(1) + "{");
164             csStr.AppendLine(GetSpace(2) + "ServiceConsumer _serviceConsumer;");
165             csStr.AppendLine(GetSpace(2) + $"public {serviceName}(ServiceConsumer serviceConsumer)");
166             csStr.AppendLine(GetSpace(2) + "{");
167             csStr.AppendLine(GetSpace(3) + "_serviceConsumer = serviceConsumer;");
168             csStr.AppendLine(GetSpace(2) + "}");
169 
170             foreach (var item in methods)
171             {
172                 var rtype = item.Value.Mothd.ReturnType;
173 
174                 if (rtype != null)
175                 {
176                     if (!_modelStrs.ContainsKey($"{spaceName}.Consumer.Model.{rtype.Name}"))
177                     {
178                         GenerateModel(spaceName, rtype);
179                     }
180                 }
181 
182                 var argsStr = new StringBuilder();
183 
184                 var argsInput = new StringBuilder();
185 
186                 if (item.Value.Pamars != null)
187                 {
188                     int i = 0;
189                     foreach (var arg in item.Value.Pamars)
190                     {
191                         i++;
192                         argsStr.Append(arg.Value.Name);
193                         argsStr.Append(" ");
194                         argsStr.Append(arg.Key);
195                         if (i < item.Value.Pamars.Count)
196                             argsStr.Append(", ");
197 
198                         if (arg.Value != null && arg.Value.IsClass)
199                         {
200                             if (!_modelStrs.ContainsKey($"{spaceName}.Consumer.Model.{arg.Value.Name}"))
201                             {
202                                 GenerateModel(spaceName, arg.Value);
203                             }
204                         }
205 
206                         argsInput.Append(", ");
207                         argsInput.Append(arg.Key);
208                     }
209                 }
210 
211                 csStr.AppendLine(GetSpace(2) + $"public {rtype.Name} {item.Key}({argsStr.ToString()})");
212                 csStr.AppendLine(GetSpace(2) + "{");
213                 csStr.AppendLine(GetSpace(3) + $"return _serviceConsumer.RemoteCall<{rtype.Name}>(\"{serviceName}\", \"{item.Key}\"{argsInput.ToString()});");
214                 csStr.AppendLine(GetSpace(2) + "}");
215 
216 
217             }
218 
219             csStr.AppendLine(GetSpace(1) + "}");
220             csStr.AppendLine("}");
221             _serviceStrs.Add(csStr.ToString());
222         }
223 
224         /// <summary>
225         /// 生成实体代码
226         /// </summary>
227         /// <typeparam name="T"></typeparam>
228         /// <param name="t"></param>
229         /// <returns></returns>
230         internal static void GenerateModel(string spaceName, Type type)
231         {
232             if (!IsModel(type)) return;
233             StringBuilder csStr = new StringBuilder();
234             csStr.AppendLine($"namespace {spaceName}.Consumer.Model");
235             csStr.AppendLine("{");
236             csStr.AppendLine($"{GetSpace(1)}public class {type.Name}");
237             csStr.AppendLine(GetSpace(1) + "{");
238             var ps = type.GetProperties();
239             foreach (var p in ps)
240             {
241                 csStr.AppendLine($"{GetSpace(2)}public {p.PropertyType.Name} {p.Name}");
242                 csStr.AppendLine(GetSpace(2) + "{");
243                 csStr.AppendLine(GetSpace(3) + "get;set;");
244                 csStr.AppendLine(GetSpace(2) + "}");
245             }
246             csStr.AppendLine(GetSpace(1) + "}");
247             csStr.AppendLine("}");
248             _modelStrs.Add($"{spaceName}.Consumer.Model.{type.Name}", csStr.ToString());
249         }
250 
251         /// <summary>
252         /// 是否是实体
253         /// </summary>
254         /// <param name="type"></param>
255         /// <returns></returns>
256         internal static bool IsModel(Type type)
257         {
258             if (type.IsArray || type.IsSealed || !type.IsClass)
259             {
260                 return false;
261             }
262             return true;
263         }
264 
265         /// <summary>
266         /// 生成客户端C#代码文件
267         /// </summary>
268         /// <param name="folder"></param>
269         /// <param name="spaceName"></param>
270         public static void Generate(string folder, string spaceName)
271         {
272             RPCMapping.RegistAll();
273 
274             GenerateProxy(spaceName);
275 
276             var filePath = Path.Combine(folder, "RPCServiceProxy.cs");
277 
278             StringBuilder sb = new StringBuilder();
279 
280             sb.AppendLine(_proxyStr);
281 
282             if (_serviceStrs != null && _serviceStrs.Count > 0)
283             {
284                 foreach (var serviceStr in _serviceStrs)
285                 {
286                     sb.AppendLine(serviceStr);
287                 }
288             }
289 
290             if (_modelStrs != null && _modelStrs.Count > 0)
291             {
292                 foreach (var entry in _modelStrs)
293                 {
294                     sb.AppendLine(entry.Value);
295                 }
296             }
297 
298             if (File.Exists(filePath))
299                 File.Delete(filePath);
300 
301             File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
302         }
303 
304 
305     }
306 }

  无论在服务端根据数量将远程调用反转本地点法、依然生成客户端代码的长河都离不开服务结构的难点。假如是基于结构文件来处理,则先要编写结构文件;服务端码农活不重事不多啊?文书档案没发你呀?啥锅都往那边甩……此处省略三千0字。其它一种艺术就是相近web
mvc接纳约定格局,写完服务业务代码后,再自动生成结构并缓存在内部存款和储蓄器里。

  1 /****************************************************************************
  2 *Copyright (c) 2018 Microsoft All Rights Reserved.
  3 *CLR版本: 4.0.30319.42000
  4 *机器名称:WENLI-PC
  5 *公司名称:Microsoft
  6 *命名空间:SAEA.RPC.Provider
  7 *文件名: ServiceTable
  8 *版本号: V1.0.0.0
  9 *唯一标识:e95f1d0b-f172-49c7-b75f-67f333504260
 10 *当前的用户域:WENLI-PC
 11 *创建人: yswenli
 12 *电子邮箱:wenguoli_520@qq.com
 13 *创建时间:2018/5/16 17:46:34
 14 *描述:
 15 *
 16 *=====================================================================
 17 *修改标记
 18 *修改时间:2018/5/16 17:46:34
 19 *修改人: yswenli
 20 *版本号: V1.0.0.0
 21 *描述:
 22 *
 23 *****************************************************************************/
 24 using SAEA.Commom;
 25 using SAEA.RPC.Model;
 26 using System;
 27 using System.Collections.Concurrent;
 28 using System.Collections.Generic;
 29 using System.Diagnostics;
 30 using System.Linq;
 31 using System.Reflection;
 32 
 33 namespace SAEA.RPC.Common
 34 {
 35     /// <summary>
 36     /// 服务类缓存表
 37     /// md5+ServiceInfo反射结果
 38     /// </summary>
 39     internal static class RPCMapping
 40     {
 41         static object _locker = new object();
 42 
 43         static HashMap<string, string, ServiceInfo> _serviceMap = new HashMap<string, string, ServiceInfo>();
 44 
 45         /// <summary>
 46         /// 本地注册RPC服务缓存
 47         /// </summary>
 48         public static HashMap<string, string, ServiceInfo> ServiceMap
 49         {
 50             get
 51             {
 52                 return _serviceMap;
 53             }
 54         }
 55 
 56         /// <summary>
 57         /// 本地注册RPC服务
 58         /// </summary>
 59         /// <param name="type"></param>
 60         public static void Regist(Type type)
 61         {
 62             lock (_locker)
 63             {
 64                 var serviceName = type.Name;
 65 
 66                 if (IsRPCService(type))
 67                 {
 68                     var methods = type.GetMethods();
 69 
 70                     var rms = GetRPCMehod(methods);
 71 
 72                     if (rms.Count > 0)
 73                     {
 74                         foreach (var m in rms)
 75                         {
 76                             var serviceInfo = new ServiceInfo()
 77                             {
 78                                 Type = type,
 79                                 Instance = Activator.CreateInstance(type),
 80                                 Mothd = m,
 81                                 Pamars = m.GetParameters().ToDic()
 82                             };
 83 
 84                             List<object> iAttrs = null;
 85 
 86                             //类上面的过滤
 87                             var attrs = type.GetCustomAttributes(true);
 88 
 89                             if (attrs != null && attrs.Length > 0)
 90                             {
 91                                 var classAttrs = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").ToList();
 92 
 93                                 if (classAttrs != null && classAttrs.Count > 0)
 94 
 95                                     iAttrs = classAttrs;
 96 
 97                             }
 98 
 99                             serviceInfo.FilterAtrrs = iAttrs;
100 
101                             //action上面的过滤
102                             var actionAttrs = m.GetCustomAttributes(true);
103 
104                             if (actionAttrs != null)
105                             {
106                                 var filterAttrs = attrs.Where(b => b.GetType().BaseType.Name == "ActionFilterAttribute").ToList();
107 
108                                 if (filterAttrs != null && filterAttrs.Count > 0)
109 
110                                     serviceInfo.ActionFilterAtrrs = filterAttrs;
111                             }
112 
113                             _serviceMap.Set(serviceName, m.Name, serviceInfo);
114                         }
115                     }
116                 }
117             }
118         }
119 
120         /// <summary>
121         /// 本地注册RPC服务
122         /// 若为空,则默认全部注册带有ServiceAttribute的服务
123         /// </summary>
124         /// <param name="types"></param>
125         public static void Regists(params Type[] types)
126         {
127             if (types != null)
128                 foreach (var type in types)
129                 {
130                     Regist(type);
131                 }
132             else
133                 RegistAll();
134         }
135         /// <summary>
136         /// 全部注册带有ServiceAttribute的服务
137         /// </summary>
138         public static void RegistAll()
139         {
140             StackTrace ss = new StackTrace(true);
141             MethodBase mb = ss.GetFrame(2).GetMethod();
142             var space = mb.DeclaringType.Namespace;
143             var tt = mb.DeclaringType.Assembly.GetTypes();
144             Regists(tt);
145         }
146 
147         /// <summary>
148         /// 判断类是否是RPCService
149         /// </summary>
150         /// <param name="type"></param>
151         /// <returns></returns>
152         public static bool IsRPCService(Type type)
153         {
154             var isService = false;
155             var cAttrs = type.GetCustomAttributes(true);
156             if (cAttrs != null)
157             {
158                 foreach (var cAttr in cAttrs)
159                 {
160                     if (cAttr is RPCServiceAttribute)
161                     {
162                         isService = true;
163                         break;
164                     }
165                 }
166             }
167             return isService;
168         }
169 
170         /// <summary>
171         /// 获取RPC方法集合
172         /// </summary>
173         /// <param name="mInfos"></param>
174         /// <returns></returns>
175         public static List<MethodInfo> GetRPCMehod(MethodInfo[] mInfos)
176         {
177             List<MethodInfo> result = new List<MethodInfo>();
178             if (mInfos != null)
179             {
180                 var isRPC = false;
181                 foreach (var method in mInfos)
182                 {
183                     if (method.IsAbstract || method.IsConstructor || method.IsFamily || method.IsPrivate || method.IsStatic || method.IsVirtual)
184                     {
185                         break;
186                     }
187                     
188                     isRPC = true;
189                     var attrs = method.GetCustomAttributes(true);
190                     if (attrs != null)
191                     {
192                         foreach (var attr in attrs)
193                         {
194                             if (attr is NoRpcAttribute)
195                             {
196                                 isRPC = false;
197                                 break;
198                             }
199                         }
200                     }
201                     if (isRPC)
202                     {
203                         result.Add(method);
204                     }
205                 }
206             }
207             return result;
208         }
209 
210         /// <summary>
211         /// 转换成字典
212         /// </summary>
213         /// <param name="parameterInfos"></param>
214         /// <returns></returns>
215         public static Dictionary<string, Type> ToDic(this ParameterInfo[] parameterInfos)
216         {
217             if (parameterInfos == null) return null;
218 
219             Dictionary<string, Type> dic = new Dictionary<string, Type>();
220 
221             foreach (var p in parameterInfos)
222             {
223                 dic.Add(p.Name, p.ParameterType);
224             }
225 
226             return dic;
227         }
228 
229 
230         /// <summary>
231         /// 获取缓存内容
232         /// </summary>
233         /// <param name="serviceName"></param>
234         /// <param name="methodName"></param>
235         /// <returns></returns>
236         public static ServiceInfo Get(string serviceName, string methodName)
237         {
238             lock (_locker)
239             {
240                 return _serviceMap.Get(serviceName, methodName);
241             }
242         }
243 
244         /// <summary>
245         /// 获取缓存内容
246         /// </summary>
247         /// <returns></returns>
248         public static List<string> GetServiceNames()
249         {
250             lock (_locker)
251             {
252                 return _serviceMap.GetHashIDs();
253             }
254         }
255         /// <summary>
256         /// 获取服务的全部信息
257         /// </summary>
258         /// <param name="serviceName"></param>
259         /// <returns></returns>
260         public static Dictionary<string, ServiceInfo> GetAll(string serviceName)
261         {
262             lock (_locker)
263             {
264                 return _serviceMap.GetAll(serviceName);
265             }
266         }
267 
268 
269 
270     }
271 }

采纳Protobuf编写1个编码解码的最简易程序

  • 在 .proto结尾的文本中定义新闻格式。
  • 行使protocol buffers编写翻译器将
    .proto结尾的文书生成对应语言的源代码(本demo使用java编写翻译器)。
  • 使用Java protocol buffer API 去读写消息。

测试

  至此多少个关键点都做到了,下边是vs2017的代码结构:

澳门葡京备用网址 3

  SAEA.冠道PCTest是测试项目,Provider为仿效服务端代码、RAV4PCServiceProxy为生成器依据劳动端生成的客户端代码,Program.cs中是利用SAEA.RAV4PC使用、测试代码:

  1 using SAEA.Commom;
  2 using SAEA.RPC.Provider;
  3 using SAEA.RPCTest.Consumer;
  4 //using SAEA.RPCTest.Consumer;
  5 using System;
  6 using System.Diagnostics;
  7 using System.Threading;
  8 using System.Threading.Tasks;
  9 
 10 namespace SAEA.RPCTest
 11 {
 12     class Program
 13     {
 14         static void Main(string[] args)
 15         {
 16             ConsoleHelper.WriteLine($"SAEA.RPC功能测试: {Environment.NewLine}   p 启动rpc provider{Environment.NewLine}   c 启动rpc consumer{Environment.NewLine}   g 启动rpc consumer代码生成器");
 17 
 18             var inputStr = ConsoleHelper.ReadLine();
 19 
 20             if (string.IsNullOrEmpty(inputStr))
 21             {
 22                 inputStr = "p";
 23             }
 24 
 25             if (inputStr == "c")
 26             {
 27                 ConsoleHelper.WriteLine("开始Consumer测试!");
 28                 ConsumerInit();
 29                 ConsoleHelper.WriteLine("回车结束!");
 30                 ConsoleHelper.ReadLine();
 31             }
 32             else if (inputStr == "a")
 33             {
 34                 ProviderInit();
 35                 ConsoleHelper.WriteLine("回车开始Consumer测试!");
 36                 ConsoleHelper.ReadLine();
 37                 ConsumerInit();
 38                 ConsoleHelper.WriteLine("回车结束!");
 39                 ConsoleHelper.ReadLine();
 40             }
 41             else if (inputStr == "g")
 42             {
 43                 ConsoleHelper.WriteLine("正在代码生成中...");
 44                 Generate();
 45                 ConsoleHelper.WriteLine("代码生成完毕,回车结束!");
 46                 ConsoleHelper.ReadLine();
 47             }
 48             else
 49             {
 50                 ProviderInit();
 51                 ConsoleHelper.WriteLine("回车结束!");
 52                 ConsoleHelper.ReadLine();
 53             }
 54         }
 55 
 56 
 57         static void ProviderInit()
 58         {
 59             ConsoleHelper.Title = "SAEA.RPC.Provider";
 60             ConsoleHelper.WriteLine("Provider正在启动HelloService。。。");
 61             var sp = new ServiceProvider(new Type[] { typeof(Provider.HelloService) });
 62             sp.Start();
 63             ConsoleHelper.WriteLine("Provider就绪!");
 64         }
 65 
 66         static void Generate()
 67         {
 68             RPC.Generater.CodeGnerater.Generate(PathHelper.Current, "SAEA.RPCTest");
 69         }
 70 
 71         static void ConsumerInit()
 72         {
 73             ConsoleHelper.Title = "SAEA.RPC.Consumer";
 74 
 75             var url = "rpc://127.0.0.1:39654";
 76 
 77             ConsoleHelper.WriteLine($"Consumer正在连接到{url}...");
 78 
 79             RPCServiceProxy cp = new RPCServiceProxy(url);
 80 
 81             ConsoleHelper.WriteLine("Consumer连接成功");
 82 
 83             ConsoleHelper.WriteLine("HelloService/Hello:" + cp.HelloService.Hello());
 84             ConsoleHelper.WriteLine("HelloService/Plus:" + cp.HelloService.Plus(1, 9));
 85             ConsoleHelper.WriteLine("HelloService/Update/UserName:" + cp.HelloService.Update(new Consumer.Model.UserInfo() { ID = 1, UserName = "yswenli" }).UserName);
 86             ConsoleHelper.WriteLine("HelloService/GetGroupInfo/Creator.UserName:" + cp.HelloService.GetGroupInfo(1).Creator.UserName);
 87             ConsoleHelper.WriteLine("HelloService/SendData:" + System.Text.Encoding.UTF8.GetString(cp.HelloService.SendData(System.Text.Encoding.UTF8.GetBytes("Hello Data"))));
 88             ConsoleHelper.WriteLine("回车启动性能测试!");
 89 
 90             ConsoleHelper.ReadLine();
 91 
 92             #region 性能测试
 93 
 94             Stopwatch sw = new Stopwatch();
 95 
 96             int count = 1000000;
 97 
 98             ConsoleHelper.WriteLine($"{count} 次实体传输调用测试中...");
 99 
100             var ui = new Consumer.Model.UserInfo() { ID = 1, UserName = "yswenli" };
101 
102             sw.Start();
103 
104             for (int i = 0; i < count; i++)
105             {
106                 cp.HelloService.Update(ui);
107             }
108             ConsoleHelper.WriteLine($"实体传输:{count * 1000 / sw.ElapsedMilliseconds} 次/秒");
109 
110             sw.Stop();
111 
112             #endregion
113 
114 
115 
116         }
117     }
118 }

  在命令行元帅SAEA.TiguanPCTest发表输入dotnet pulish -r
win7-x64后运维exe如下:

澳门葡京备用网址 4

迄今一个使用方便、高质量rpc就从头形成了。

转发请标明本文来源:
越多内容欢迎star/fork作者的github:
借使发现本文有怎么样难点和别的提出,也随时欢迎沟通~

概念三个Student.proto文件

syntax ="proto2";

package com.zhihao.miao.protobuf;

//optimize_for 加快解析的速度
option optimize_for = SPEED;
option java_package = "com.zhihao.miao.protobuf";
option java_outer_classname="DataInfo";

message Student{
    required string name = 1;
    optional int32 age = 2;
    optional string address = 3;
}

在Java项目中,除非你已经显著钦赐了java_package,否则package
用作Java的包名。固然你提供java_package,您依然应该定义2个package,以制止在Protocol Buffers名称空间和非Java语言中的名称争执。

在package的概念之后,大家得以看看七个概念的java选项:java_packagejava_outer_classnamejava_package钦定您生成的类应该存放的Java包名称。
借使没有显明钦命它,将会动用package定义的name作为包名,但那个名称日常不是相符的Java包名称(因为它们平常不以域名先河)。
java_outer_classname慎选定义应该包括此文件中全体类的类名。
固然您不明了地交给1个java_outer_classname,它将由此将文件名转移为驼峰的法子来变化。
例如,暗许情况下,“my_proto.proto”将运用“MyProto”作为外部类名称。

每个成分上的“= 1”,“=
2”标记标识字段在二进制编码中使用的绝无仅有“标签”。你可以将常常应用也许另行的字段标注成1-15,因为在举行编码的时候因为少四个字节实行编码,所以功效更高。

required:必须提供该字段的值,不然被认为并未开头化。尝试营造一个未早先化的值被会抛出RuntimeException。解析一个为最先化的音信会抛出IOException。除此之外与optional一样。
optional:能够安装或不设置该字段。
要是未设置可选字段值,则运用暗许值。
repeated:字段大概重新任意次数(包含零)。
重复值的相继将保存在protocol buffer中。
将另行的字段视为动态大小的数组。(本列子中尚无字段定义成repeated类型,定义成repeated品类其实正是java中List类型的字段。

郑重使用required类型,将required花色的字段更改为optional会有一对标题,而将optional项目标字段更改为required品种,则并未难题。

编译

运用protocol buffers编写翻译器将相应的.proto文件编写翻译成对应的类
关于编写翻译器的安装,下载地址:

澳门葡京备用网址 5

下载页面图示

修改环境变量

➜  vim .bash_profile
export PATH=/Users/naeshihiroshi/software/work/protoc-3.3.0-osx-x86_64/bin
➜  source .bash_profile
➜  which protoc
/Users/naeshihiroshi/software/work/protoc-3.3.0-osx-x86_64/bin/protoc

进入项目目录,执行编写翻译语句如下:

➜  netty_lecture git:(master) ✗ protoc --java_out=src/main/java  src/protobuf/Student.proto   

--java_out前边第二个参数钦点代码的路径,具体的包名在.proto文件中的java_package钦命了,第3个钦点要编写翻译的proto文件。

自动生成的类名是DataInfo(在java_outer_classname中钦命了),自动生成的类太长,那边就不列出来了。

编纂类别化反连串化测试类

package com.zhihao.miao.protobuf;

//实际使用protobuf序列化框架客户端将对象转译成字节数组,然后通过协议传输到服务器端,服务器端可以是其他的语言框架(比如说python)将
//字节对象反编译成java对象
public class ProtobuffTest {
    public static void main(String[] args) throws Exception{
        DataInfo.Student student = DataInfo.Student.newBuilder().
                setName("张三").setAge(20).setAddress("北京").build();

        //将对象转译成字节数组,序列化
        byte[] student2ByteArray = student.toByteArray();

        //将字节数组转译成对象,反序列化
        DataInfo.Student student2 = DataInfo.Student.parseFrom(student2ByteArray);

        System.out.println(student2.getName());
        System.out.println(student2.getAge());
        System.out.println(student2.getAddress());
    }
}

举办测试类,控制台打字与印刷:

张三
20
北京

Google Protobuf与netty结合

protobuf做为连串化的一种方法,序列化之后通过怎么着的载体在网络中传输?

运用netty使得经过protobuf系列化的对象足以经过互联网通讯举行客户端和服务器的新闻通讯。客户端应用protobuf将目标系列化成字节码,而服务器端通过protobuf将目的反类别化成原来对象。

写1个选择Protobuf作为种类化框架,netty作为传输层的最简易的demo,必要描述:

  • 客户端传递贰个User对象给服务端(User对象包罗姓名,年龄,密码)
  • 客户端接收客户端的User对象并且将其对应的银行账户等音信上报给客户端

概念的.proto文件如下:

syntax ="proto2";

package com.zhihao.miao.netty.sixthexample;

option optimize_for = SPEED;
option java_package = "com.zhihao.miao.test.day06";
option java_outer_classname="DataInfo";

message RequestUser{
    optional string user_name = 1;
    optional int32 age = 2;
    optional string password = 3;
}

message ResponseBank{
    optional string bank_no = 1;
    optional double money = 2;
    optional string bank_name=3;
}

使用Protobuf编写翻译器实行编写翻译,生成DataInfo对象,

劳动器端代码:

package com.zhihao.miao.test.day06;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class ProtoServer {
    public static void main(String[] args) throws Exception{
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup wokerGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,wokerGroup).channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ProtoServerInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            wokerGroup.shutdownGracefully();
        }
    }
}

服务端ProtoServerInitializer(初叶化连接):

package com.zhihao.miao.test.day06;


import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;


public class ProtoServerInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        //服务器端接收的是客户端RequestUser对象,所以这边将接收对象进行解码生产实列
        pipeline.addLast(new ProtobufDecoder(DataInfo.RequestUser.getDefaultInstance()));
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufEncoder());

        pipeline.addLast(new ProtoServerHandler());
    }
}

自定义服务端的电脑:

package com.zhihao.miao.test.day06;


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ProtoServerHandler extends SimpleChannelInboundHandler<DataInfo.RequestUser> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DataInfo.RequestUser msg) throws Exception {
        System.out.println(msg.getUserName());
        System.out.println(msg.getAge());
        System.out.println(msg.getPassword());

        DataInfo.ResponseBank bank = DataInfo.ResponseBank.newBuilder().setBankName("中国工商银行")
                .setBankNo("6222222200000000000").setMoney(560000.23).build();

        ctx.channel().writeAndFlush(bank);
    }
}

客户端:

package com.zhihao.miao.test.day06;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

public class ProtoClient {

    public static void main(String[] args) throws Exception{
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .handler(new ProtoClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("localhost",8899).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            eventLoopGroup.shutdownGracefully();
        }
    }
}

客户端开头化连接(ProtoClientInitializer),

package com.zhihao.miao.test.day06;


import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;

public class ProtoClientInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();

        //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        //将接收到的二进制文件解码成具体的实例,这边接收到的是服务端的ResponseBank对象实列
        pipeline.addLast(new ProtobufDecoder(DataInfo.ResponseBank.getDefaultInstance()));
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
        //Google Protocol Buffers编码器
        pipeline.addLast(new ProtobufEncoder());

        pipeline.addLast(new ProtoClientHandler());
    }
}

自定义客户端处理器:

package com.zhihao.miao.test.day06;


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

public class ProtoClientHandler extends SimpleChannelInboundHandler<DataInfo.ResponseBank> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DataInfo.ResponseBank msg) throws Exception {
        System.out.println(msg.getBankNo());
        System.out.println(msg.getBankName());
        System.out.println(msg.getMoney());
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        DataInfo.RequestUser user = DataInfo.RequestUser.newBuilder()
                .setUserName("zhihao.miao").setAge(27).setPassword("123456").build();
        ctx.channel().writeAndFlush(user);
    }
}

运营服务器端和客户端,服务器控制台打字与印刷:

七月 03, 2017 11:12:03 下午 io.netty.handler.logging.LoggingHandler channelRead
信息: [id: 0xa1a63b58, L:/0:0:0:0:0:0:0:0:8899] READ: [id: 0x08c534f3, L:/127.0.0.1:8899 - R:/127.0.0.1:65448]
七月 03, 2017 11:12:03 下午 io.netty.handler.logging.LoggingHandler channelReadComplete
信息: [id: 0xa1a63b58, L:/0:0:0:0:0:0:0:0:8899] READ COMPLETE
zhihao.miao
27
123456

客户端控制台打字与印刷:

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
6222222200000000000
中国工商银行
560000.23

总结

本节大家应用Google Protobuf概念消息体格式,使用Netty作为互联网传输层框架。其实半数以上中华VPC框架底层达成都以采用类别化框架和NIO通讯框架举办整合。上面还会学习基于Protobuf
3.0协议的Grpc框架(谷歌(Google)基于Protobuf
3.0协议的2个跨语言的rpc框架,特别心心念念的去探听rpc框架)。

参考资料

官方网站
澳门葡京备用网址 ,指南
java指南

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website