跨語言RPC:使用Java客戶端調用Go服務端的JSON-RPC服務

在分布式系統開發中,不同編程語言之間進行通信是一個常見的需求。通過遠程過程調用(RPC)技術,我們可以讓不同的程序像調用本地方法一樣調用遠程的服務。本文將介紹如何使用Go語言編寫一個簡單的JSON-RPC服務,并使用Java作為客戶端來跨語言調用這個服務。

一、背景介紹

在之前的文章中,我們已經了解了如何使用Go語言構建一個基本的RPC服務。然而,默認情況下,Go語言的net/rpc包使用的是一種名為Gob的序列化格式,這限制了它只能與支持Gob編碼的語言進行交互。為了實現跨語言的RPC調用,我們可以采用更通用的數據交換格式——如JSON。Go語言的net/rpc/jsonrpc包就提供了這樣的功能,允許我們在不修改服務邏輯的情況下,輕松地與其他語言進行交互。

二、Go服務端實現

首先,我們需要創建一個Go服務端,該服務端將提供一個簡單的“Hello”服務。以下是完整的代碼示例:

package mainimport ("fmt""net""net/rpc""net/rpc/jsonrpc"
)// 定義一個服務結構體
type HelloService struct{}// 定義一個遠程可調用的方法
func (s *HelloService) Hello(request string, reply *string) error {fmt.Printf("Received request: %s\n", request)*reply = "hello " + requestreturn nil
}func main() {// 監聽本地 1234 端口listen, err := net.Listen("tcp", ":1234")if err != nil {panic(err)}defer listen.Close()// 注冊服務err = rpc.RegisterName("HelloService", new(HelloService))if err != nil {panic(err)}// 接受連接并處理for {conn, err := listen.Accept()if err != nil {continue}go jsonrpc.ServeConn(conn)}
}

關鍵點解釋:

  • 服務定義:我們定義了一個HelloService結構體,并為其添加了一個Hello方法。這個方法接收一個字符串參數,并返回一個經過處理后的字符串。
  • 注冊服務:使用rpc.RegisterName函數將服務注冊到RPC框架中,這里我們指定了服務名稱為"HelloService"
  • 啟動服務:監聽指定端口并接受連接,然后使用jsonrpc.ServeConn來處理每一個新的連接。

代碼解析

代碼片段作用說明
type HelloService自定義的服務結構體,用于封裝遠程方法
func (s *HelloService) Hello(...)這是一個“導出方法”,可以被外部調用
net.Listen("tcp", ":1234")創建 TCP 監聽器,監聽本地 1234 端口
rpc.RegisterName("HelloService", ...)將服務注冊為 RPC 框架的一部分,服務名是?"HelloService"
jsonrpc.ServeConn(conn)使用 JSON-RPC 協議處理每個連接,自動解析請求、調用方法并返回結果

? 總結:Go 服務端本質上是一個 TCP 服務器,使用 JSON-RPC 協議與客戶端通信。客戶端發送 JSON 請求,服務端執行對應方法后,返回 JSON 響應。

三、Java客戶端實現

接下來,我們將編寫一個Java客戶端來調用上述Go服務端提供的“Hello”服務。以下是完整的Java代碼示例:

import org.json.JSONObject;import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;public class GoJsonRpcClient {
import org.json.JSONObject;import java.io.*;
import java.net.Socket;public class GoJsonRpcClient {public static void main(String[] args) throws IOException {String hostname = "127.0.0.1"; // Go服務端IP地址int port = 1234; // Go服務端監聽端口try (Socket socket = new Socket(hostname, port)) {OutputStream output = socket.getOutputStream();PrintWriter writer = new PrintWriter(output, true);InputStream input = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(input));JSONObject jsonRequest = new JSONObject();jsonRequest.put("jsonrpc", "2.0");jsonRequest.put("method", "HelloService.Hello");jsonRequest.put("params", new String[]{"Bob"});jsonRequest.put("id", 1);writer.println(jsonRequest.toString());String jsonResponse = reader.readLine();if (jsonResponse != null && !jsonResponse.isEmpty()) {JSONObject jsonObject = new JSONObject(jsonResponse);System.out.println("Received response: " + jsonObject.toString());if (jsonObject.has("result")) {System.out.println("Result: " + jsonObject.getString("result"));}} else {System.out.println("No response or empty response.");}} catch (IOException e) {throw new RuntimeException(e);}}
}public static void main(String[] args) {String hostname = "127.0.0.1"; // Go服務端IP地址int port = 1234; // Go服務端監聽端口try (Socket socket = new Socket(hostname, port)) {PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));JSONObject jsonRequest = new JSONObject();jsonRequest.put("jsonrpc", "2.0");jsonRequest.put("method", "HelloService.Hello");jsonRequest.put("params", new String[]{"Bob"}); // 請求參數jsonRequest.put("id", 1); // 請求IDwriter.println(jsonRequest.toString());String jsonResponse = reader.readLine();if (jsonResponse != null && !jsonResponse.isEmpty()) {JSONObject jsonObject = new JSONObject(jsonResponse);System.out.println("Received response: " + jsonObject.toString());if (jsonObject.has("result")) {System.out.println("Result: " + jsonObject.getString("result"));}} else {System.out.println("No response or empty response.");}} catch (Exception e) {throw new RuntimeException(e);}}
}

關鍵點解釋:

  • 請求構建:我們使用org.json.JSONObject來構造符合JSON-RPC規范的請求對象。在這個例子中,我們的請求包含了一個方法名(對應于Go服務端的Hello方法)、一組參數以及一個唯一的請求ID。
  • 發送請求:通過套接字連接向Go服務端發送構造好的請求。
  • 接收響應:從輸入流中讀取服務端返回的響應,并解析其中的結果字段。

代碼解析

代碼片段作用說明
Socket socket = new Socket(hostname, port)創建一個 TCP 連接到 Go 服務端
PrintWriter writer = new PrintWriter(output, true)獲取輸出流,用于向服務端發送請求
BufferedReader reader = new BufferedReader(...)獲取輸入流,用于接收服務端響應
JSONObject jsonRequest = new JSONObject()構造 JSON 請求對象
jsonRequest.put("method", "HelloService.Hello")設置要調用的服務方法
jsonRequest.put("params", new String[]{"Bob"})設置參數列表
writer.println(jsonRequest.toString())發送請求
String jsonResponse = reader.readLine()讀取服務端返回的 JSON 響應
jsonObject.getString("result")提取返回值中的?result?字段

? 總結:Java 客戶端通過 Socket 建立 TCP 連接,構造符合 JSON-RPC 規范的請求,發送給 Go 服務端,并等待響應。

四、測試與驗證

確保Go服務端正在運行后,執行Java客戶端程序。如果一切配置正確,你應該能夠看到類似以下的輸出結果:

Received response: {"jsonrpc":"2.0","result":"hello Bob","id":1}
Result: hello Bob

這表明Java客戶端成功地調用了Go服務端的“Hello”方法,并收到了預期的響應。

五、總結

JSON-RPC 的核心思想

角色功能
服務端(Go)監聽 TCP 端口,接收 JSON-RPC 請求,調用本地方法,返回 JSON-RPC 響應
客戶端(Java)建立 TCP 連接,構造 JSON-RPC 請求,發送并讀取響應
關鍵點使用 JSON 作為數據格式,TCP 作為傳輸層,實現跨語言通信

通過這篇文章,我們學習了如何使用Go語言構建一個JSON-RPC服務端,并使用Java作為客戶端進行跨語言調用。這種方法不僅打破了語言之間的界限,還利用了JSON這種輕量級的數據交換格式,使得不同平臺和語言之間的集成變得更加簡單高效。

關于使用JSON-RPC替換RPC原本的序列化協議Gob的目的和優點可以看上一篇內容。

希望這篇博客能幫助你在實際項目中更好地應用RPC技術。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84103.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84103.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84103.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

UE5 創建AI控制器、AI行為樹和黑板

UE5 創建AI控制器、AI行為樹和黑板 一、創建AI控制器AIController(大腦) 二、創建AI行為樹和黑板 1:AI人工智能 2:行為樹 3:黑板 三、AI行為樹藍圖和添加黑板 1:添加黑板(腦電波)…

CDN加速導致CLS升高圖片托管服務器的3個選擇標準!

許多網站為了提升加載速度,會采用CDN加速服務分發圖片等靜態資源 這樣做可能導致CLS(累積布局偏移)指標升高,拖累SEO評分。 這一問題通常源于CDN的異步加載機制或圖片尺寸未預定義,使得頁面布局在渲染過程中頻繁變動。…

MySQL(77)如何設置自動備份任務?

設置自動備份任務可以確保你的數據庫定期備份,防止數據丟失。以下是如何使用 Bash 腳本和 Cron 任務在 Linux 系統上設置 MySQL 數據庫的自動備份任務的詳細步驟和代碼示例。 1. 編寫備份腳本 首先,我們需要編寫一個備份腳本。這個腳本將包含執行備份的…

.NET 開發中全局數據存儲的幾種方式

文章目錄 一、靜態類與靜態成員實現方式特點優缺點 二、應用程序配置系統1. appsettings.json (ASP.NET Core)使用方式2. 用戶設置 (WinForms/WPF)特點 三、依賴注入容器ASP.NET Core 示例特點 四、內存緩存 (IMemoryCache)實現方式特點 五、分布式緩存 (IDistributedCache)實現…

人才爭奪戰關鍵期,AI如何賦能招聘效率倍增、精準選拔

數智化轉型浪潮席卷全球的今天,人才作為企業核心競爭力的地位日益凸顯。而在傳統招聘流程,尤其是面試環節正面臨效率瓶頸、體驗短板等多項挑戰,典型如: 耗時冗長的篩選與安排;難以避免的主觀評價偏差;海量…

介紹下分布式ID的技術實現及應用場景

什么是分布式ID 分布式ID是指在分布式系統中生成的特定范圍內唯一的標識符,如訂單號、商品ID、鏈路追蹤TraceID。 隨著業務發展,對分布式ID的要求越來越高,其中最基本的要求如下 全局唯一:在任何節點、任何時間生成的ID都必須是…

【leetcode-字母異位詞分組】

排序法 public List<List<String>> groupAnagrams(String[] strs) {//最終值List<List<String>> result new ArrayList<>();//排序法HashMap<String,List<String>> map new HashMap<>(); //遍歷strfor(String str : strs){/…

langchain從入門到精通(九)——ChatGPT/Playground手動模擬記憶功能

1. 摘要緩沖混合記憶 摘要緩沖混合記憶中&#xff0c;所需的模塊有&#xff1a; chat_message_history&#xff1a;存儲歷史消息列表。moving_summary_buffer&#xff1a;移除消息的匯總字符串。summary_llm&#xff1a;生成摘要的 LLM&#xff0c;接收 summary&#xff08;當…

docker單點安裝Hadoop

1、Docker中拉取jdk8鏡像 拉取鏡像 docker pull openjdk:8-jdk 查看jdk docker run -it openjdk:8-jdk bash which java 2、安裝ubuntu源 拉取鏡像 docker pull ubuntu:22.04 保存 docker save -o ubuntu-22.04.tar.gz ubuntu:22.04 移動到自己想要的目錄 mv /roo…

uniapp項目之小兔鮮兒小程序商城(二) 首頁的實現:自定義導航欄,輪撥圖,前臺分類,熱門推薦,猜你喜歡,下拉刷新,骨架屏

文章目錄 零.首頁最終效果一.自定義導航欄1.新建pages/index/components/CustomNavbar.vue首頁子組件2.在首頁pages/index/index.vue中引入3.隱藏默認導航欄修改標題顏色4.適配不同機型使用到了uniapp的一個api:獲取屏幕邊界到安全區域的距離在子組件中使用 二.輪撥圖1.新建 sr…

RustDesk自建遠程服務器

目錄 服務端 環境linux 安裝 開放端口 客戶端配置 下載客戶端 安裝后配置網絡 參考&#xff1a;RustDesk自建遠程服務器_rustdesk自建服務器-CSDN博客 服務端 環境 linux 安裝 下載 wget https://github.com/rustdesk/rustdesk-server/releases/download/1.1.8-2/r…

【Axure高保真原型】圖片伸縮展示列表

今天和大家分享圖片伸縮展示列表的3個原型案例&#xff0c;模版都是用中繼器制作的&#xff0c;所以使用也很方便&#xff0c;在中繼器表格里導入對應的圖片&#xff0c;即可自動生成交互效果&#xff0c;具體效果可以點擊下方視頻觀看或打開下方預覽地址查看哦 【原型效果】 …

keil新建工程文件結構和每個文件的作用解析(標準庫版本)

通過網盤分享的文件:STM32工程模板 鏈接:https://pan.baidu.com/s/1YPFgXu1kwuwsCVxrXFSjZg?pwd=1111 提取碼: 1111 --來自百度網盤超級會員v5的分享 這個工程模版是來源于B站江科大的模版,每個人搭建工程文件結構不一樣,僅供參考。 工程文件目錄結構如圖所示 1、DebugC…

【AI論文】Saffron-1:LLM安全保證的推理縮放范例

摘要&#xff1a;現有的安全保證研究主要集中在培訓階段的協調&#xff0c;以向LLM灌輸安全行為。 然而&#xff0c;最近的研究表明這些方法容易受到各種越獄攻擊。 同時&#xff0c;推理擴展顯著提高了LLM推理能力&#xff0c;但在安全保證方面仍未得到探索。 為了解決這一差距…

LLM 支持的基于意圖的分類 網絡釣魚電子郵件

大家讀完覺得有幫助記得關注和點贊&#xff01;&#xff01;&#xff01; 抽象 網絡釣魚攻擊仍然是現代網絡安全的重大威脅&#xff0c;因為它們成功地欺騙了人類和旨在保護他們的防御機制。傳統的檢測系統主要關注用戶在收件箱中看不到的電子郵件元數據。此外&#xff0c;這些…

C++新特性技術發展路徑和時間

C 的新特性發展路徑和時間線是一個持續演進的過程。以下是一個概覽&#xff0c;涵蓋了主要的 C 標準及其關鍵特性&#xff0c;以及它們發布的時間&#xff1a; C 標準版本及發布時間線: C98 (ISO/IEC 14882:1998): 第一個正式的 C 標準。 發布時間: 1998年關鍵特性: 標準模板庫…

OpenAI 如何在激烈的AI人才爭奪戰中搶占先機?

在這個快速發展的人工智能時代&#xff0c;OpenAI 正處于一個至關重要的發展階段。隨著技術的不斷進步&#xff0c;人工智能行業的競爭日益激烈。如何在這場巨大的競爭中立于不敗之地&#xff0c;成為了每一個AI公司的核心挑戰。就在近日&#xff0c;OpenAI 的新招聘主管華金?…

【Java學習筆記】Java繪圖基礎

Java繪圖基礎 一、Java 坐標體系 1. 像素的概念 計算機在屏幕上顯示的內容都是由屏幕上的每一個像素組成的 例如&#xff0c;計算機顯示器的分辨率是 800600&#xff0c;表示計算機屏幕上的每一行由 800 個點組成&#xff0c;共有 600 行&#xff0c;整個計算機屏幕共有 480…

資深Java工程師的面試題目(一)基礎到高級概述

以下是幾道面向資深Java工程師的面試題目&#xff0c;涵蓋了從基礎知識到高級概念及參考答案&#xff1a; 1. Java內存模型和垃圾回收 問題: 請解釋一下Java的內存模型&#xff0c;并描述不同類型的內存區域。如何選擇適合特定應用需求的垃圾收集器&#xff1f;請比較幾種常…

Spring Retry:優雅地實現方法重試機制

前言 在實際的軟件開發中&#xff0c;尤其是在涉及網絡請求、數據庫操作或外部服務調用的場景下&#xff0c;我們常常會遇到一些臨時性故障&#xff08;Transient Failures&#xff09;&#xff0c;例如網絡波動、數據庫連接超時、第三方 API 暫時不可用等。面對這些問題&…