日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

网络篇 - rpc协议的应用web3j

發(fā)布時(shí)間:2024/1/1 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 网络篇 - rpc协议的应用web3j 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

最近的公司區(qū)塊鏈錢(qián)包,用到了以太坊的官方開(kāi)發(fā)庫(kù) web3j。web3j?是Java版本的以太坊 rpc-json?接口協(xié)議封裝實(shí)現(xiàn),如果需要將你的 Java 或安卓應(yīng)用接入以太坊,或者希望用 Java 開(kāi)發(fā)一個(gè)錢(qián)包應(yīng)用,那么 web3j 完全能滿(mǎn)足你的需求。

?

目錄:

  • rpc 簡(jiǎn)介
  • rpc 和 http 對(duì)比
  • json-rpc 簡(jiǎn)介
  • web3j 調(diào)用
  • web3j json-rpc 實(shí)現(xiàn)
  • ?

    ?

    1.?rpc 簡(jiǎn)介

    rpc (?Remote Procedure Call)?— 遠(yuǎn)程過(guò)程調(diào)用,它是一種通過(guò)網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請(qǐng)求服務(wù),而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議。rpc 協(xié)議假定某些傳輸協(xié)議的存在,如 tcp?或 udp,為通信程序之間傳輸信息數(shù)據(jù)。在 OSI 網(wǎng)絡(luò)通信模型中,rpc?跨越了傳輸層和應(yīng)用層。rpc 使得開(kāi)發(fā)包括網(wǎng)絡(luò)分布式多程序在內(nèi)的應(yīng)用程序更加容易。

    我從 google 上找了一張 rpc 模型圖,幫助大家理解下:

    ?

    ?

    ?

    2.?rpc 和 http 對(duì)比

    目前有很多 Java 的 rpc?框架,有基于 Json 的,有基于 XML,也有基于二進(jìn)制對(duì)象的。rpc 和 平常用的 http/https 到底有什么區(qū)別,不都是寫(xiě)一個(gè)服務(wù)然后在客戶(hù)端調(diào)用嗎?

    在 http 和 rpc?的選擇上可能有些人是迷惑的,主要是因?yàn)?#xff0c;有些 rpc?框架配置復(fù)雜,如果走 http 也能完成同樣的功能,那么為什么要選擇 rpc,而不是更容易上手的 http 來(lái)實(shí)現(xiàn)?

    從以下幾個(gè)點(diǎn)來(lái)分析:

    (1)?傳輸協(xié)議

    • rpc?可以基于 tcp 協(xié)議 (可以省去了 http 報(bào)頭等一系列東西,rpc 并沒(méi)有規(guī)定數(shù)據(jù)傳輸格式,這個(gè)格式可以任意指定,不同的 rpc 協(xié)議,數(shù)據(jù)格式不一定相同),也可以基于 http 協(xié)議。
    • http 只能基于 http 協(xié)議。

    (2) 傳輸效率

    • rpc?使用自定義的 tcp 協(xié)議,可以讓請(qǐng)求報(bào)文體積更小,或者使用 http 2.0協(xié)議,也可以很好的減少報(bào)文的體積,提高傳輸效率。
    • http?如果是基于 http 1.1的協(xié)議,請(qǐng)求中會(huì)包含很多無(wú)用的內(nèi)容,如果是基于 http 2.0,那么簡(jiǎn)單的封裝以下是可以作為一個(gè) rpc 來(lái)使用的,這時(shí)標(biāo)準(zhǔn) rpc?框架更多的是服務(wù)治理。

    (3) 性能消耗,主要在于序列化和反序列化的耗時(shí)

    • rpc?可以基于 thrift 實(shí)現(xiàn)高效的二進(jìn)制傳輸。
    • http 大部分是通過(guò) json 來(lái)實(shí)現(xiàn)的,字節(jié)大小和序列化耗時(shí)都比 thrift 要更消耗性能。

    (3) 負(fù)載均衡

    • rpc 基本都自帶了負(fù)載均衡策略。
    • http 需要配置 Nginx,HAProxy來(lái)實(shí)現(xiàn)。

    (3) 服務(wù)治理 (下游服務(wù)新增,重啟,下線(xiàn)時(shí)如何不影響上游調(diào)用者)

    • rpc 能做到自動(dòng)通知,不影響上游。
    • http 需要事先通知,修改 Nginx/HAProxy 配置。

    早期的 webservice,現(xiàn)在熱門(mén)的 dubbo,都是 rpc?的典型。rpc?服務(wù)主要是針對(duì)大型企業(yè)的,而 http 服務(wù)主要是針對(duì)小企業(yè)的,因?yàn)?rpc 效率更高,而 http 服務(wù)開(kāi)發(fā)迭代會(huì)更快。

    ?

    ?

    ?

    3.?json-rpc 簡(jiǎn)介

    json-rpc 是基于 json 的跨語(yǔ)言遠(yuǎn)程調(diào)用協(xié)議,比 xml-rpc、webservice 等基于文本的協(xié)議數(shù)據(jù)傳輸格小,相對(duì) hessian、java-rpc 等二進(jìn)制協(xié)議便于調(diào)試、實(shí)現(xiàn)、擴(kuò)展,是很優(yōu)秀的一種遠(yuǎn)程調(diào)用協(xié)議。眼下主流語(yǔ)言都已有 json-rpc 的實(shí)現(xiàn)框架,Java 語(yǔ)言中較好的 json-rpc 實(shí)現(xiàn)框架有 jsonrpc4j、jpoxy、json-rpc。

    json-rpc 協(xié)議很簡(jiǎn)單,發(fā)起遠(yuǎn)程調(diào)用時(shí)向服務(wù)端數(shù)據(jù)傳輸格式例如以下:?

    { "method": "helloCoder", "params": ["Hello JSON-RPC"], "id": 1}

    參數(shù)說(shuō)明:

    • method:調(diào)用的方法名。
    • params:方法傳入的參數(shù),若無(wú)參數(shù)則傳入 []。
    • id: 調(diào)用標(biāo)識(shí)符,用于標(biāo)示一次遠(yuǎn)程調(diào)用過(guò)程。

    服務(wù)端收到調(diào)用請(qǐng)求,處理方法調(diào)用,將方法調(diào)用結(jié)果返回給調(diào)用方,返回?cái)?shù)據(jù)格式:

    {"result": "Hello JSON-RPC","error": null,"id": 1 }

    參數(shù)說(shuō)明:?

    • result: 方法返回值,若無(wú)返回值,則返回 null。若調(diào)用錯(cuò)誤,返回 null。
    • error :調(diào)用時(shí)錯(cuò)誤,無(wú)錯(cuò)誤返回 null。?
    • id : 調(diào)用標(biāo)識(shí)符,與調(diào)用方傳入的標(biāo)識(shí)符一致。?

    以上就是 json-rpc 協(xié)議規(guī)范,很簡(jiǎn)單,便于各種語(yǔ)言實(shí)現(xiàn)。

    ?

    ?

    ?

    4.?web3j 調(diào)用

    在 gradle 中添加依賴(lài):

    // 以太坊開(kāi)發(fā)庫(kù) compile 'org.web3j:core:3.3.1-android'

    拿我們公司的區(qū)塊鏈錢(qián)包為例,獲取余額和轉(zhuǎn)幣調(diào)用了 web3j 的方法,它封裝了 json-rpc 的調(diào)用過(guò)程,先看看獲取余額的代碼:

    @Overridepublic BigInteger getBalance(String address) throws CTXCException {CTXCException.checkNetwork();EthGetBalance ethGetBalance;try {ethGetBalance = getWeb3j().ethGetBalance(address, PENDING).send();if (ethGetBalance.hasError())throw new CTXCException(true, ethGetBalance.getError().getMessage());} catch (Exception e) {throw new CTXCException(true, e);}String response = ethGetBalance.getRawResponse();Web3jResponseProcessor processor = new Web3jResponseProcessor(response).process();if (processor.isSuccess())return TokenBigConverter.toBigInteger(processor.getRawResponse().result);return BigInteger.ZERO;}

    再看看轉(zhuǎn)賬的調(diào)用:

    @Overridepublic String sendTransaction(String fromAddress, String password, String toAddress, BigInteger gasPrice,BigInteger gasLimit, BigInteger amount, String payload) throws CTXCException {CTXCException.checkNetwork();try {EthGetTransactionCount ethGetTransactionCount = getWeb3j().ethGetTransactionCount(fromAddress, PENDING).sendAsync().get();BigInteger nonce = ethGetTransactionCount.getTransactionCount();payload = payload == null ? "" : payload;RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, toAddress, amount, payload);Credentials credentials = Credentials.create(WalletManagerService.instance().exportPrivateKey(fromAddress, password));byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);String hexValue = Numeric.toHexString(signedMessage);EthSendTransaction ethSendTransaction = getWeb3j().ethSendRawTransaction(hexValue).send();if (ethSendTransaction.hasError())throw new CTXCException(true, ethSendTransaction.getError().getMessage());Web3jResponseProcessor processor = new Web3jResponseProcessor(ethSendTransaction.getRawResponse()).process();if (processor.isSuccess())return processor.getRawResponse().result;} catch (Exception e) {throw new CTXCException(true, e.getMessage());}return "";}

    比如:getWeb3j().ethGetBalance(address, PENDING).send(),這樣就能獲取到某個(gè) erc20地址的余額。而 web3j 封裝了 json-rpc 的調(diào)用過(guò)程,在以太坊的開(kāi)發(fā)文檔上,對(duì)獲取余額的 rpc 調(diào)用是這樣的:

    可以看到,正是上面說(shuō)的 json-rpc 協(xié)議的格式。

    ?

    ?

    ?

    5.?web3j json-rpc 實(shí)現(xiàn)

    以?getWeb3j().ethGetBalance(address, PENDING).send() 作為入口分析。

    實(shí)現(xiàn)在?JsonRpc2_0Web3j 這個(gè)類(lèi):

    public Request<?, EthGetBalance> ethGetBalance(String address, DefaultBlockParameter defaultBlockParameter) {return new Request("eth_getBalance", Arrays.asList(address, defaultBlockParameter.getValue()), this.web3jService, EthGetBalance.class);}

    將 json-rpc 方法名"eth-getBalance"和Array.asList 將參數(shù)轉(zhuǎn)換成 List 傳入,返回一個(gè) Request 對(duì)象:

    public class Request<S, T extends Response> {private static AtomicLong nextId = new AtomicLong(0L);// jsonrpc 版本private String jsonrpc = "2.0";// 方法名private String method;// 參數(shù)列表private List<S> params;// jsonrpc 參數(shù) idprivate long id;private Web3jService web3jService;private Class<T> responseType;public Request() {}public Request(String method, List<S> params, Web3jService web3jService, Class<T> type) {this.method = method;this.params = params;this.id = nextId.getAndIncrement();this.web3jService = web3jService;this.responseType = type;}public String getJsonrpc() {return this.jsonrpc;}public void setJsonrpc(String jsonrpc) {this.jsonrpc = jsonrpc;}public String getMethod() {return this.method;}public void setMethod(String method) {this.method = method;}public List<S> getParams() {return this.params;}public void setParams(List<S> params) {this.params = params;}public long getId() {return this.id;}public void setId(long id) {this.id = id;}public T send() throws IOException {return this.web3jService.send(this, this.responseType);}public Future<T> sendAsync() {return this.web3jService.sendAsync(this, this.responseType);}public Observable<T> observable() {return (new RemoteCall(new Callable<T>() {public T call() throws Exception {return Request.this.send();}})).observable();} }

    這個(gè)類(lèi)封裝了請(qǐng)求參數(shù)和行為,接著看里面的?send() 方法:

    public T send() throws IOException {return this.web3jService.send(this, this.responseType);}

    調(diào)用 web3jService的 send() 方法進(jìn)行 json-rpc 調(diào)用,傳入 request 對(duì)象和返回類(lèi)型。Web3jService 是一個(gè)接口,那這邊調(diào)的是哪個(gè)實(shí)現(xiàn)類(lèi)呢?看看?web3j 對(duì)象的構(gòu)造代碼:

    web3j = Web3jFactory.build(new HttpService(web3jRpcURL, true));

    我這邊傳入的是 HttpService (實(shí)現(xiàn)?Web3jService 接口):

    protected abstract InputStream performIO(String var1) throws IOException;public <T extends Response> T send(Request request, Class<T> responseType) throws IOException {String payload = this.objectMapper.writeValueAsString(request);InputStream result = this.performIO(payload);return result != null ? (Response)this.objectMapper.readValue(result, responseType) : null;}

    可以看到 send() 方法:

    String payload = this.objectMapper.writeValueAsString(request);

    先將 request 對(duì)象轉(zhuǎn)換成 json,即上面 json-rpc 協(xié)議的請(qǐng)求格式:

    { "method": "helloCoder", "params": ["Hello JSON-RPC"], "id": 1}

    然后執(zhí)行?performIO() 進(jìn)行 rpc 調(diào)用,下面是 HttpService 的 performIO() 的實(shí)現(xiàn):

    protected InputStream performIO(String request) throws IOException {RequestBody requestBody = RequestBody.create(JSON_MEDIA_TYPE, request);Headers headers = this.buildHeaders();Request httpRequest = (new okhttp3.Request.Builder()).url(this.url).headers(headers).post(requestBody).build();Response response = this.httpClient.newCall(httpRequest).execute();if (response.isSuccessful()) {ResponseBody responseBody = response.body();return responseBody != null ? this.buildInputStream(responseBody) : null;} else {throw new ClientConnectionException("Invalid response received: " + response.body());}}

    rpc 的過(guò)程用的是 okhttp3,上面說(shuō)過(guò) rpc 可以基于 http 協(xié)議,這邊的 httpClient 需要傳入一個(gè) http 協(xié)議版本,這邊用的是默認(rèn)的:

    DEFAULT_PROTOCOLS = Util.immutableList(new Protocol[]{Protocol.HTTP_2, Protocol.HTTP_1_1});

    而以太坊官方的 web3j json-rpc 的文檔中也寫(xiě)到:

    可以看到它們的服務(wù)提供的 json-rpc 支持 http 進(jìn)行消息傳遞。

    ?

    ?

    總結(jié)

    以上是生活随笔為你收集整理的网络篇 - rpc协议的应用web3j的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。