<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                一個完整的RPC流程,可以用下面這張圖來描述: ![](https://img.kancloud.cn/14/90/1490426b8fa1b25cfcb26f8dc7ff2429_308x240.png) 其中左邊的Client,對應的就是前面的Service A,而右邊的Server,對應的則是Service B。 1.Service A的應用層代碼中,調用了Calculator的一個實現類的add方法,希望執行一個加法運算; 2.這個Calculator實現類,內部并不是直接實現計算器的加減乘除邏輯,而是通過遠程調用Service B的RPC接口,來獲取運算結果,因此稱之為**Stub**; 3.Stub怎么和Service B建立遠程通訊呢?這時候就要用到**遠程通訊工具**了,也就是圖中的**Run-time Library**,這個工具將幫你實現遠程通訊的功能,比如Java的**Socket**,就是這樣一個庫,當然,你也可以用基于Http協議的**HttpClient**,或者其他通訊工具類,都可以,**RPC并沒有規定說你要用何種協議進行通訊**; 4.Stub通過調用通訊工具提供的方法,和Service B建立起了通訊,然后將請求數據發給Service B。需要注意的是,由于底層的網絡通訊是基于**二進制格式**的,因此這里Stub傳給通訊工具類的數據也必須是二進制,比如calculator.add(1,2),你必須把參數值1和2放到一個Request對象里頭(這個Request對象當然不只這些信息,還包括要調用哪個服務的哪個RPC接口等其他信息),然后**序列化**為二進制,再傳給通訊工具類,這一點也將在下面的代碼實現中體現; 5.二進制的數據傳到Service B這一邊了,Service B當然也有自己的通訊工具,通過這個通訊工具接收二進制的請求; 6.既然數據是二進制的,那么自然要進行**反序列化**了,將二進制的數據反序列化為請求對象,然后將這個請求對象交給Service B的Stub處理; 7.和之前的Service A的Stub一樣,這里的Stub也同樣是個“假玩意”,它所負責的,只是去解析請求對象,知道調用方要調的是哪個RPC接口,傳進來的參數又是什么,然后再把這些參數傳給對應的RPC接口,也就是Calculator的實際實現類去執行。很明顯,如果是Java,那這里肯定用到了**反射**。 8.RPC接口執行完畢,返回執行結果,現在輪到Service B要把數據發給Service A了,怎么發?一樣的道理,一樣的流程,只是現在Service B變成了Client,Service A變成了Server而已:Service B反序列化執行結果->傳輸給Service A->Service A反序列化執行結果 -> 將結果返回給Application,完畢。 ----------- RPC簡單示例: 首先是Client端的應用層怎么發起RPC,ComsumerApp: ``` public class ComsumerApp { public static void main(String[] args) { Calculator calculator = new CalculatorRemoteImpl(); int result = calculator.add(1, 2); } } ``` **通過一個CalculatorRemoteImpl,我們把RPC的邏輯封裝進去了,客戶端調用時感知不到遠程調用的麻煩**。 CalculatorRemoteImpl類代碼: ``` public class CalculatorRemoteImpl implements Calculator { public int add(int a, int b) { List<String> addressList = lookupProviders("Calculator.add"); String address = chooseTarget(addressList); try { Socket socket = new Socket(address, PORT); // 將請求序列化 CalculateRpcRequest calculateRpcRequest = generateRequest(a, b); ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); // 將請求發給服務提供方 objectOutputStream.writeObject(calculateRpcRequest); // 將響應體反序列化 ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); Object response = objectInputStream.readObject(); if (response instanceof Integer) { return (Integer) response; } else { throw new InternalError(); } } catch (Exception e) { log.error("fail", e); throw new InternalError(); } } } ``` 分布式應用下,一個服務可能有多個實例,比如Service B,可能有ip地址為198.168.1.11和198.168.1.13兩個實例,lookupProviders,其實就是在尋找要調用的服務的實例列表。在分布式應用下,通常會有一個**服務注冊中心**,來提供查詢實例列表的功能。 查到實例列表之后要調用哪一個實例呢,只時候就需要chooseTarget了,其實內部就是一個**負載均衡**策略。 由于我們這里只是想實現一個簡單的RPC,所以暫時不考慮服務注冊中心和負載均衡,因此代碼里寫死了返回ip地址為127.0.0.1。 代碼繼續往下走,我們這里用到了Socket來進行遠程通訊,同時利用**ObjectOutputStream**的writeObject和**ObjectInputStream**的readObject,來實現序列化和反序列化。 最后再來看看Server端的實現,和Client端非常類似,ProviderApp: ``` public class ProviderApp { private Calculator calculator = new CalculatorImpl(); public static void main(String[] args) throws IOException { new ProviderApp().run(); } private void run() throws IOException { ServerSocket listener = new ServerSocket(9090); try { while (true) { Socket socket = listener.accept(); try { // 將請求反序列化 ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); Object object = objectInputStream.readObject(); log.info("request is {}", object); // 調用服務 int result = 0; if (object instanceof CalculateRpcRequest) { CalculateRpcRequest calculateRpcRequest = (CalculateRpcRequest) object; if ("add".equals(calculateRpcRequest.getMethod())) { result = calculator.add(calculateRpcRequest.getA(), calculateRpcRequest.getB()); } else { throw new UnsupportedOperationException(); } } // 返回結果 ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); objectOutputStream.writeObject(new Integer(result)); } catch (Exception e) { log.error("fail", e); } finally { socket.close(); } } } finally { listener.close(); } } } ``` Server端主要是通過ServerSocket的accept方法,來接收Client端的請求,接著就是反序列化請求->執行->序列化執行結果,最后將二進制格式的執行結果返回給Client。 **就這樣我們實現了一個簡陋而又詳細的RPC。** 說它簡陋,是因為這個實現確實比較挫。 說它詳細,是因為它一步一步的演示了一個RPC的執行流程,方便了解RPC的內部機制。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看