以太坊rpc介面編寫
⑴ rpc是什麼如何處理
遠程過程調用 (RPC) 是一種協議,程序可使用這種協議向網路中的另一台計算機上的程序請求服務。由於使用 RPC 的程序不必了解支持通信的網路協議的情況,因此 RPC 提高了程序的互操作性。在 RPC 中,發出請求的程序是客戶程序,而提供服務的程序是伺服器。 x0dx0aRPC 中處理 TCP/IP 上的消息交換的部分存在一個缺陷。錯誤地處理格式不正確的消息會導致出現錯誤。這種特定的錯誤會影響底層的 DCOM 介面,此介面偵聽 TCP/IP 埠 135。通過發送格式不正確的 RPC 消息,攻擊者可以使一台計算機上的 RPC 服務出現問題,進而使任意代碼得以執行。 x0dx0a遠程過程調用 (RPC) 是 Windows 操作系統使用的一個協議。RPC 提供了一種進程間通信機制,通過這一機制,在一台計算機上運行的程序可以順暢地執行某個遠程系統上的代碼。該協議本身是從 OSF(開放式軟體基礎)RPC 協議衍生出來的,只是增加了一些 Microsoft 特定的擴展。 x0dx0ax0dx0aRPC 中處理通過 TCP/IP 的消息交換的部分有一個漏洞。此問題是由錯誤地處理格式不正確的消息造成的。這種特定的漏洞影響分布式組件對象模型 (DCOM) 與 RPC 間的一個介面,此介面偵聽 TCP/IP 埠 135。此介面處理客戶端計算機向伺服器發送的 DCOM 對象激活請求(例如通用命名約定 (UNC) 路徑)。 x0dx0ax0dx0a為利用此漏洞,攻擊者可能需要向遠程計算機上的 135 埠發送特殊格式的請求。 x0dx0ax0dx0a減輕影響的因素: x0dx0ax0dx0a為利用此漏洞,攻擊者可能需要擁有向遠程計算機上的 135 埠發送精心編造的請求的能力。對於 Intranet 環境,此埠通常是可以訪問的;但對於通過 Internet 相連的計算機,防火牆通常會封堵 135 埠。如果沒有封堵該埠,或者在 Intranet 環境中,攻擊者就不需要有任何其他特權。 x0dx0ax0dx0a最佳做法是封堵所有實際上未使用的 TCP/IP 埠。因此,大多數連接到 Internet 的計算機應當封堵 135 埠。RPC over TCP 不適合在 Internet 這樣存在著危險的環境中使用。像 RPC over HTTP 這樣更堅實的協議適用於有潛在危險的環境。 x0dx0a這是一個緩沖區溢出漏洞。成功利用此漏洞的攻擊者有可能獲得對遠程計算機的完全控制。這可能使攻擊者能夠對伺服器隨意執行操作,包括更改網頁、重新格式化硬碟或向本地管理員組添加新的用戶。 x0dx0ax0dx0a要發動此類攻擊,攻擊者需要能夠向 RPC 服務發送一條格式不正確的消息,從而造成目標計算機受制於人,攻擊者可以在它上面執行任意代碼。 x0dx0ax0dx0a防範來自 Internet 的遠程 RPC 攻擊的最佳方法是:將防火牆配置為封堵 135 埠。RPC over TCP 不適合在 Internet 這樣存在著危險的環境中使用。 x0dx0ax0dx0a此漏洞是由於 Windows RPC 服務在某些情況下不能正確檢查消息輸入而造成的。如果攻擊者在 RPC 建立連接後發送某種類型的格式不正確的 RPC 消息,則會導致遠程計算機上與 RPC 之間的基礎分布式組件對象模型 (DCOM) 介面出現問題,進而使任意代碼得以執行。
⑵ DApp開發入門
本文僅介紹以太坊系列的DApp開發,其他鏈原理差不太多。
MetaMask安裝完成並運行後,可以在Chrome控制台列印 MetaMask注入的window.ethereum對象
關於ethereum對象,我們只需要關心 ethereum.request 就足夠了,MetaMask 使用 ethereum.request(args) 方法 來包裝 RPC API。這些 API 基於所有以太坊客戶端公開的介面。 簡單來說錢包交互的大部分操作都是由 request() 方法實現,通過傳入不同的方法名來區分。
⚠️ 即使ethereum對象中提供了chainId,isMetaMask,selectAddress屬性,我們也不能完全相信這些屬性,他們是不穩定或不標准,不建議使用。我們可以通過上面說的request方法,拿到可靠的數據 。
錢包通過method方法名,進行對應的實現 以獲取錢包地址為例
調用 ethereum.request({ method: "eth_requestAccounts" }) ,錢包實現了該方法,那麼就可以拿到錢包的地址了。
MetaMask注入的 window.ethereum 就是一個Provider,一個RPC節點也是一個Provider,通過Provider,我們有了訪問區塊鏈的能力。 在連接到錢包的情況下,通常使用錢包的Provider就可以了, ethers.providers.Web3Provider(ethereum)
如果只需要查詢一些區塊鏈數據,可以使用EtherscanProvider 和 InfuraProvider 連接公開的 第三方節點服務提供商 。JsonRpcProvider 和 IpcProvider 允許連接到我們控制或可以訪問的以太坊節點。
獲取當前賬戶余額
獲取最新區塊號
其他RPC操作,可以通過 JSON-RPC 查看。
通過 ethers.js 可以連接ERC20的合約,合約編譯後會生成ABI,合約部署後,會生成合約地址,開發者通過 ABI和合約地址 ,對合約發送消息。
合約中的方法大致分為兩種: 視圖方法(免費),非視圖方法(消耗Gas) ,可以通過ABI查看方法類型。
⚠️ ERC20需要多加關注的是 Approve() 方法以及 transfer() 和 transferFrom() 的區別 ,授權過的代幣,被授權的那一方,可以通過調用 transferFrom() 方法,轉走你授權數量內的代幣,所以授權是一個很危險的操作,假設你授權了一個不良的合約,那你會面臨授權的token被轉走的風險,即使你沒有泄露私鑰助記詞。
便利三方庫: web3-react use-wallet
文檔: doc.metamask.io ethers
⑶ Infura API 獲取以太坊當前配置鏈 ID - 區塊鏈數據開發實戰
簡介:Infura 是以太坊和 IPFS 的 API 服務提供商。Infura 一開始只是為 ConsenSys 內部項目提供穩定可靠的 RPC 訪問,後來隨著以太坊生態發展,他們意識到自己可以起到更大作用,於是開始面向開發者提供公共 API 服務。本文整理使用 Infura API 獲取以太坊當前配置鏈 ID 的實現。
Infura 是以太坊和 IPFS 的 API 服務提供商。Infura 一開始只是為 ConsenSys 內部項目提供穩定可靠的 RPC 訪問,後來隨著以太坊生態發展,他們意識到自己可以起到更大作用,於是開始面向開發者提供公共 API 服務。
本文整理使用 Infura API 獲取以太坊當前配置鏈 ID 的實現。
Infura API 官方文檔: https://infura.io/docs
使用 API 需要申請 Project ID ,ID 是免費申請的,申請流程為「注冊 - 登錄 - 創建新項目」,不需要審核,幾分鍾就能搞定。
Infura API 標准請求埠格式:
本例中我們使用基於 HTTP 的以太坊主網 JSON-RPC 埠:
Infura API 獲取以太坊當前配置鏈 ID:
Curl 示例:
Node.js 示例:
返回的 JSON 示例:
返回當前鏈 ID 的大整數。
Infura API 服務思維導圖:
我們有一個區塊鏈知識星球,做區塊鏈前沿資料的歸納整理以方便大家檢索查詢使用,也是國內頂尖區塊鏈技術社區,歡迎感興趣的朋友加入。如果你對上面內容有疑問,也可以加入知識星球提問我:
⑷ 使用thrift來構建rpc服務
最近整理下以前用過thrift來構建rpc服務寫的東西,也發布到github上去了,地址: https://github.com/Xiazki/airlift
目前還在完善,簡單介紹下:
airlift是一個基於thrift的rpc服務框架,利用 Swift (停止維護了:pensive:)提供的註解來創建簡單可序列化的thrift類型和服務。利用zookeeper提供了動態的注冊和服務發現
並增加了客戶端的負載均衡、重試機制。
一個簡單的例子
定義一個 ThriftStruct 參考 Swift Codec .
使用 ThriftService 定義一個提供服務的介面,並實現這個介面,如下:
介面實現類:
使用 AirliftServer 啟動服務,服務監聽9013, withRegistryUrls("127.0.0.1:2181") 注冊zookeeper地址,多個地址用 ; 拼接。
使用 AirliftClientFactory 來創建客戶端代理。
⑸ 一學就會,手把手教你用Go語言調用智能合約
智能合約調用是實現一個 DApp 的關鍵,一個完整的 DApp 包括前端、後端、智能合約及區塊 鏈系統,智能合約的調用是連接區塊鏈與前後端的關鍵。
我們先來了解一下智能合約調用的基礎原理。智能合約運行在以太坊節點的 EVM 中。因此要 想調用合約必須要訪問某個節點。
以後端程序為例,後端服務若想連接節點有兩種可能,一種是雙 方在同一主機,此時後端連接節點可以採用 本地 IPC(Inter-Process Communication,進 程間通信)機制,也可以採用 RPC(Remote Procere Call,遠程過程調用)機制;另 一種情況是雙方不在同一台主機,此時只能採用 RPC 機制進行通信。
提到 RPC, 讀者應該對 Geth 啟動參數有點印象,Geth 啟動時可以選擇開啟 RPC 服務,對應的 默認服務埠是 8545。。
接著,我們來了解一下智能合約運行的過程。
智能合約的運行過程是後端服務連接某節點,將 智能合約的調用(交易)發送給節點,節點在驗證了交易的合法性後進行全網廣播,被礦工打包到 區塊中代表此交易得到確認,至此交易才算完成。
就像資料庫一樣,每個區塊鏈平台都會提供主流 開發語言的 SDK(Software Development Kit,軟體開發工具包),由於 Geth 本身就是用 Go 語言 編寫的,因此若想使用 Go 語言連接節點、發交易,直接在工程內導入 go-ethereum(Geth 源碼) 包就可以了,剩下的問題就是流程和 API 的事情了。
總結一下,智能合約被調用的兩個關鍵點是節點和 SDK。
由於 IPC 要求後端與節點必須在同一主機,所以很多時候開發者都會採用 RPC 模式。除了 RPC,以太坊也為開發者提供了 json- rpc 介面,本文就不展開討論了。
接下來介紹如何使用 Go 語言,藉助 go-ethereum 源碼庫來實現智能合約的調用。這是有固定 步驟的,我們先來說一下總體步驟,以下面的合約為例。
步驟 01:編譯合約,獲取合約 ABI(Application Binary Interface,應用二進制介面)。 單擊【ABI】按鈕拷貝合約 ABI 信息,將其粘貼到文件 calldemo.abi 中(可使用 Go 語言IDE 創建該文件,文件名可自定義,後綴最好使用 abi)。
最好能將 calldemo.abi 單獨保存在一個目錄下,輸入「ls」命令只能看到 calldemo.abi 文件,參 考效果如下:
步驟 02:獲得合約地址。注意要將合約部署到 Geth 節點。因此 Environment 選擇為 Web3 Provider。
在【Environment】選項框中選擇「Web3 Provider」,然後單擊【Deploy】按鈕。
部署後,獲得合約地址為:。
步驟 03:利用 abigen 工具(Geth 工具包內的可執行程序)編譯智能合約為 Go 代碼。abigen 工具的作用是將 abi 文件轉換為 Go 代碼,命令如下:
其中各參數的含義如下。 (1)abi:是指定傳入的 abi 文件。 (2)type:是指定輸出文件中的基本結構類型。 (3)pkg:指定輸出文件 package 名稱。 (4)out:指定輸出文件名。 執行後,將在代碼目錄下看到 funcdemo.go 文件,讀者可以打開該文件欣賞一下,注意不要修改它。
步驟 04:創建 main.go,填入如下代碼。 注意代碼中 HexToAddress 函數內要傳入該合約部署後的地址,此地址在步驟 01 中獲得。
步驟 04:設置 go mod,以便工程自動識別。
前面有所提及,若要使用 Go 語言調用智能合約,需要下載 go-ethereum 工程,可以使用下面 的指令:
該指令會自動將 go-ethereum 下載到「$GOPATH/src/github.com/ethereum/go-ethereum」,這樣還算 不錯。不過,Go 語言自 1.11 版本後,增加了 mole 管理工程的模式。只要設置好了 go mod,下載 依賴工程的事情就不必關心了。
接下來設置 mole 生效和 GOPROXY,命令如下:
在項目工程內,執行初始化,calldemo 可以自定義名稱。
步驟 05:運行代碼。執行代碼,將看到下面的效果,以及最終輸出的 2020。
上述輸出信息中,可以看到 Go 語言會自動下載依賴文件,這就是 go mod 的神奇之處。看到 2020,相信讀者也知道運行結果是正確的了。
⑹ 搭建geth私有鏈和聯盟鏈網路
操作系統:linux或Mac OS
安裝geth執行以下命令:
linux:sudo apt-get install ethereum
Mac OS:brew install ethereum
直接創建兩個geth的工作目錄,用於之後的組建聯盟鏈的使用:
mkdir eth-private1
mkdir eth-private2
首先 cd eth-private1 進入節點1的工作目錄該目錄下執行下面命令
geth --datadir data --nodiscover console (data是之後geth節點的數據目錄,可自行修改)
使用geth自帶的工具 puppeth 用於生成創世區塊,過程如下:
puppeth
+-----------------------------------------------------------+
| Welcome to puppeth, your Ethereum private network manager |
| |
| This tool lets you create a new Ethereum network down to |
| the genesis block, bootnodes, miners and ethstats servers |
| without the hassle that it would normally entail. |
| |
| Puppeth uses SSH to dial in to remote servers, and builds |
| its network components out of Docker containers using the |
| docker-compose toolset. |
+-----------------------------------------------------------+
Please specify a network name to administer (no spaces, please)
輸入私鏈名稱後,會出現二級菜單,現在2:配置一個新的創世快
What would you like to do? (default = stats)
再次出現二級菜單,讓你選擇共識機制(這里採用poa共識)
Which consensus engine to use? (default = clique)
Ethash - proof-of-work(PoW) :工作量證明,通過算力達成共識 (以太坊就是使用這種方式)
Clique - proof-of-authority(PoA): 權威證明、通過預先設定的權威節點來負責達成共識 (不消耗算力,一般用於私有鏈測試開發)
如果選擇Pow的共識方法,直接輸入1,回車即可。
如果選擇PoA的共識方法,輸入2後會提示讓你選擇處快的間隔時間,一般測試開發使用可以設置相對的將處快時間設置較少5秒即可,然後會讓你選擇哪個賬戶來作為權威生成區塊(至少有一個,輸入剛才創建的賬戶,若只是單節點就輸入那個節點目錄生成的地址,若想組建聯盟鏈就填寫生成的兩個地址)
How many seconds should blocks take? (default = 15)
選擇好共識機制後會讓你指定給那些賬號初始化ether(至少有一個),輸入我們剛才創建的賬戶地址回車即可。
Which accounts should be pre-funded? (advisable at least one)
選擇輸入私有鏈的網路ID,任意數字即可(不能為1,1是公鏈),也可以不輸入會給定一個隨機數作為私有鏈的網路ID
Specify your chain/network ID if you want an explicit one (default = random)
選擇導出創世區塊配置文件
選擇導出創世區塊配置文件的保存路徑,可以保存到當前目錄,直接按回車即可
Which file to save the genesis into? (default = my-private-chain.json)
INFO [02-09|14:56:33] Exported existing genesis block
這樣就完成了創世區塊文件的配置了,直接退出puppeth即可。
輸入命令 geth --datadir data init private.json 其中data自己制定,private.json就是剛才生成的創世區塊
若出現如圖錯誤:
輸入命令:
geth --datadir data --syncmode full --port 2001 --networkid 1234 --rpc --rpcport "8545" --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcapi "db,eth,net,web3,personal,admin,clique" --nodiscover console 進入控制台
--datadir data:節點的數據目錄
--syncmode full:塊同步的方式(若只是單節點可不填)
--port 2001: 網卡監聽埠
--networkid 1234:網路標識符
--rpc:開啟rpc服務
--rpcport "8545":rpc服務的埠
--rpccorsdomain "*":允許跨域請求的域名列表(逗號分隔)(瀏覽器強制)
--rpcaddr "0.0.0.0" :HTTP-RPC伺服器介面地址(默認值:「localhost」)
--rpcapi "db,eth,net,web3,personal,admin,clique":基於HTTP-RPC介面提供的API(私有鏈可以任意開發,公有鏈需要謹慎)
--nodiscover:不允許節點自動加入
若想搭建聯盟鏈,必須保證創世區塊一致,進入到剛才創建的eth-private2的目錄
將之前生成的創世區塊拷貝過來,初始化創世區塊,然後使用啟動命令啟動分別啟動兩個節點,進入控制台,使用 admin.nodeInfo 命令獲取節點的信息
總結:
兩個伺服器部署兩個節點是可以聯通的,但是只能使用兩個節點對應的地址進行挖礦,所以只能是兩個節點對應兩個地址進行挖礦,使用poa共識,當一個節點掛掉,挖礦停止,因為poa共識挖礦必須超過50%的節點進行錢增,現在只是兩個節點,掛掉一個節點挖礦就會停止等待另一個節點的確認,停掉的節點可以通過正常運作的節點信息重新連接到網路中。
問題:
同步塊有可能報錯情況:
1:Synchronisation failed "retrieved hash chain is invalid" 解決目前找到的方法是removedb 數據目錄 ,重新init創世區塊
2:內存溢出初步確認為開啟rpc服務造成的,有可能伺服器惡意被黑,暴力破解密碼,佔有內存,解決,將伺服器的ip設置一條防火牆
若存在問題可給本人留言或訪問本人的github: https://github.com/qi-shuo/geth-document 記錄了一些本人搭建使用的命令
⑺ 求一個用C++編寫的RPC方法的例子
去這個專欄看下,我記得當初就是在這學的,最後還有源代碼下載,講得很詳細,祝你學習進步
http://www.cppblog.com/jb8164/archive/2009/10/14/48368.html
第1步:編寫 IDL(Interface Description Language,介面描述語言)文件
-------------------------------------------------------------------------
IDL 是一個通用的工業標准語言,大家應該不陌生,因為 COM 裡面也是用它來描述介面的。
Hello.idl:
[
uuid("4556509F-618A-46CF-AB3D-ED736ED66477"), // 唯一的UUID,用 GUIDGen 生成
version(1.0)
]
interface HelloWorld
{
// 我們定義的方法
void Hello([in,string]const char * psz);
void Shutdown(void);
}
一個可選的文件是應用程序配置文件(.acf),它的作用是對 RPC 介面進行配置,例如下面的 Hello.acf 文件:
Hello.acf:
[
implicit_handle(handle_t HelloWorld_Binding)
]
interface HelloWorld
{
}
上面定義了 implicit_handle,這樣客戶端將綁定句柄 HelloWorld_Binding 了,後面的客戶端代碼中我們會看到。
編譯 IDL 文件:
>midl Hello.idl
Microsoft (R) 32b/64b MIDL Compiler Version 6.00.0366
Copyright (c) Microsoft Corporation 1991-2002. All rights reserved.
Processing .\Hello.idl
Hello.idl
Processing .\Hello.acf
Hello.acf
我們可以看到自動生成了 Hello.h, Hello_s.c, Hello_c.c 文件,這些叫做 rpc stub 程序,不過我們可以不管這個概念,
我們只需要知道 Hello.h 裡面定義了一個
extern RPC_IF_HANDLE HelloWorld_v1_0_s_ifspec;
這個 RPC_IF_HANDLE 將在後面用到。
第2步:編寫服務端程序
-------------------------------------------------------------------------
第1步中我們已經約定了調用的介面,那麼現在我們開始實現其服務端。代碼如下:
server.c
#include <stdlib.h>
#include <stdio.h>
#include "Hello.h" // 引用MIDL 生成的頭文件
/**
* 這是我們在IDL 中定義的介面方法
* 需要注意一點,IDL 裡面的聲明是:void Hello([in,string]const char * psz);
* 但是這里變成了const unsigned char *,為什麼呢?
* 參見MSDN 中的MIDL Command-Line Reference -> /char Switch
* 默認的編譯選項,對 IDL 中的char 按照unsigned char 處理
*/
void Hello(const unsigned char * psz)
{
printf("%s\n", psz);
}
/** 這也是我們在IDL 中定義的介面方法,提供關閉server 的機制*/
void Shutdown(void)
{
// 下面的操作將導致 RpcServerListen() 退出
RpcMgmtStopServerListening(NULL);
RpcServerUnregisterIf(NULL, NULL, FALSE);
}
int main(int argc,char * argv[])
{
// 用Named Pipe 作為RPC 的通道,這樣EndPoint 參數就是Named Pipe 的名字
// 按照Named Pipe 的命名規范,\pipe\pipename,其中pipename 可以是除了\
// 之外的任意字元,那麼這里用一個GUID 串來命名,可以保證不會重復
RpcServerUseProtseqEp((unsigned char *)"ncacn_np", 20, (unsigned char *)"\\pipe\\{8dd50205-3108-498f-96e8-dbc4ec074cf9}", NULL);
// 注冊介面,HelloWorld_v1_0_s_ifspec 是在MIDL 生成的Hello.h 中定義的
RpcServerRegisterIf(HelloWorld_v1_0_s_ifspec, NULL, NULL);
// 開始監聽,本函數將一直阻塞
RpcServerListen(1,20,FALSE);
return 0;
}
// 下面的函數是為了滿足鏈接需要而寫的,沒有的話會出現鏈接錯誤
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
return(malloc(len));
}
void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
{
free(ptr);
}
編譯:
>cl /D_WIN32_WINNT=0x500 server.c Hello_s.c rpcrt4.lib
用於 80x86 的 Microsoft (R) 32 位 C/C++ 優化編譯器 14.00.50727.42 版
版權所有(C) Microsoft Corporation。保留所有權利。
server.c
Hello_s.c
正在生成代碼...
Microsoft (R) Incremental Linker Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.
/out:server.exe
server.obj
Hello_s.obj
rpcrt4.lib
編譯時為什麼要指定 _WIN32_WINNT=0x500 呢?因為如果沒有的話會報告下面的錯誤:
Hello_s.c(88) : fatal error C1189: #error : You need a Windows 2000 or later to
run this stub because it uses these features:
第3步:編寫客戶端程序
-------------------------------------------------------------------------
客戶端的代碼:
client.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Hello.h" // 引用MIDL 生成的頭文件
int main(int argc, char * argv[])
{
unsigned char * pszStringBinding = NULL;
if ( argc != 2 )
{
printf("Usage:%s <Hello Text>\n", argv[0]);
return 1;
}
// 用Named Pipe 作為RPC 的通道。參見server.c 中的RpcServerUseProtseqEp() 部分
// 第3 個參數NetworkAddr 如果取NULL,那麼就是連接本機服務
// 否則要取\\\\servername 這樣的格式,例如你的計算機名為jack,那麼就是\\jack
RpcStringBindingCompose( NULL, (unsigned char*)"ncacn_np", /*(unsigned char*)"\\\\servername"*/ NULL, (unsigned char*)"\\pipe\\{8dd50205-3108-498f-96e8-dbc4ec074cf9}", NULL, &pszStringBinding );
// 綁定介面,這里要和 Hello.acf 的配置一致,那麼就是HelloWorld_Binding
RpcBindingFromStringBinding(pszStringBinding, & HelloWorld_Binding );
// 下面是調用服務端的函數了
RpcTryExcept
{
if ( _stricmp(argv[1], "SHUTDOWN") == 0 )
{
Shutdown();
}
else
{
Hello((unsigned char*)argv[1]);
}
}
RpcExcept(1)
{
printf( "RPC Exception %d\n", RpcExceptionCode() );
}
RpcEndExcept
// 釋放資源
RpcStringFree(&pszStringBinding);
RpcBindingFree(&HelloWorld_Binding);
return 0;
}
// 下面的函數是為了滿足鏈接需要而寫的,沒有的話會出現鏈接錯誤
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t len)
{
return(malloc(len));
}
void __RPC_USER midl_user_free(void __RPC_FAR *ptr)
{
free(ptr);
}
編譯:
>cl /D_WIN32_WINNT=0x500 client.c Hello_c.c rpcrt4.lib
用於 80x86 的 Microsoft (R) 32 位 C/C++ 優化編譯器 14.00.50727.42 版
版權所有(C) Microsoft Corporation。保留所有權利。
client.c
Hello_c.c
正在生成代碼...
Microsoft (R) Incremental Linker Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.
/out:client.exe
client.obj
Hello_c.obj
rpcrt4.lib
第4步:測試:
-------------------------------------------------------------------------
運行 server.exe,將彈出一個 console 窗口,等待客戶端調用。
運行客戶端 client.exe:
>client hello
可以看到 server.exe 的 console 窗口出現 hello 的字元串。
>client shutdown
server.exe 退出。