用C++的進階模版特性實現一個不需要IDL的RPC

來源:互聯網
上載者:User

目前已經全部完成,並且取得了非常好的效果 。

使用該RPC的簡短代碼:

 rpc函數的傳回值是 rpc_ret_t,主要是為了避免專門為void傳回值的函數編寫特化代碼   

//////////////////////////////////////////////////////////////////////////<br />// sample usage...<br />// test.h </p><p>typedef std::vector<unsigned> vint_vec;</p><p>class AsyncInterface : public GlobaleScope<br />{<br />public:<br />BEGIN_RPC_ADD_MF(AsyncInterface)<br />RPC_ADD_MF(get_val)<br />RPC_ADD_MF(get_len)<br />RPC_ADD_MF(squareVec)<br />RPC_ADD_MF(multiVec)<br />END_RPC_ADD_MF()</p><p>RPC_DECLARE_MF(get_val, (rpc_in<int> x))<br />RPC_DECLARE_MF(get_len, (const std::string& x))<br />RPC_DECLARE_MF(squareVec, (vint_vec& x))<br />RPC_DECLARE_MF(multiVec, (vint_vec& z, vint_vec& x, vint_vec& y))<br />};<br />RPC_TYPEDEF_PTR(AsyncInterface);</p><p>// more convenient way than AsyncInterface...<br />BEGIN_RPC_INTERFACE(SampleRPC_Interface2, SessionScope)<br />RPC_ADD_MF(get_val)<br />RPC_ADD_MF(get_len)<br />END_RPC_ADD_MF()<br />RPC_DECLARE_MF(get_val, (rpc_in<int> x))<br />RPC_DECLARE_MF(get_len, (const std::string& x))<br />END_RPC_INTERFACE()<br />

 

 // async_client.cpp</p><p>#include <iostream><br />#include <febird/rpc/client.h><br />#include <febird/io/SocketStream.h></p><p>using namespace std;<br />using namespace febird;<br />using namespace febird::rpc;</p><p>#include "../test.h"<br />#pragma comment(lib, "Ws2_32.lib")</p><p>void printVec(const vint_vec& vec)<br />{<br />for (int i = 0; i != vec.size(); ++i)<br />{<br />cout << "vec[" << i << "]=" << vec[i] << "/n";<br />}<br />}</p><p>class AsyncImpl : public AsyncInterface<br />{<br />public:<br />AsyncImpl()<br />{<br />this->multiVec.set_async_callback(&AsyncImpl::on_multiVec);<br />}<br />private:<br />void on_multiVec(const client_packet_base& packet, vint_vec& z, vint_vec& x, vint_vec& y)<br />{<br />printf("AsyncImpl::on_multiVec/n");<br />printf("ret=%u, z=%u, x=%u, y=%u/n", packet.retv, z.size(), x.size(), y.size());<br />}<br />};<br />RPC_TYPEDEF_PTR(AsyncImpl);</p><p>int main0(int argc, char* argv[])<br />try {<br />auto_ptr<SocketStream> cs(ConnectSocket("127.0.0.1:8001"));<br />rpc_client<PortableDataInput, PortableDataOutput> client(cs.get());</p><p>AsyncImplPtr obj1;<br />SampleRPC_Interface2Ptr obj2;</p><p>client.create(obj1, "obj1");<br />client.create(obj2, "obj2");</p><p>int ret;<br />ret = client.retrieve(obj2, "obj2");</p><p>rpc_ret_t val = obj1->get_val(100);<br />cout << "obj1->get_val(100)=" << val << "/n";</p><p>val = obj1->get_len("hello, world!");<br />cout << "obj1->get_len(/"hello, world!/")=" << val << "/n";</p><p>std::vector<unsigned> vec;<br />vec.push_back((1));<br />vec.push_back((2));<br />vec.push_back((3));<br />vec.push_back((4));<br />vec.push_back((11));<br />vec.push_back((22));<br />vec.push_back((33));<br />vec.push_back((44));</p><p>val = obj1->squareVec(vec);<br />printVec(vec);<br />val = obj1->squareVec(vec);<br />printVec(vec);</p><p>std::vector<unsigned> vec2;<br />for (int i = 0; i != vec.size(); ++i)<br />{<br />vec2.push_back(i + 1);<br />}<br />//obj1->multiVec.on_return = &AsyncInterface::on_multiVec;<br />for (int i = 0; i < 5; ++i)<br />{<br />std::vector<unsigned> vec3;<br />obj1->multiVec.async(vec3, vec, vec2);<br />cout << "obj1->multiVec(vec3, vec, vec2) = " << val << "/n";<br />printVec(vec3);<br />}<br />client.wait_pending_async();<br />return 0;<br />}<br />catch (const std::exception& exp)<br />{<br />printf("exception: what=%s/n", exp.what());<br />return 1;<br />}</p><p>int main(int argc, char* argv[])<br />{<br />#if defined(_WIN32) || defined(_WIN64)<br />WSADATA information;<br />WSAStartup(MAKEWORD(2, 2), &information);<br />int ret = main0(argc, argv);<br />WSACleanup();<br />return ret;<br />#else<br />return main0(argc, argv);<br />#endif<br />}</p><p>

 

// async_server.cpp</p><p>#include <febird/rpc/server.h><br />#include <febird/io/SocketStream.h><br />#include <iostream></p><p>using namespace febird;<br />using namespace febird::rpc;</p><p>#include "../test.h"<br />#pragma comment(lib, "Ws2_32.lib")</p><p>// use macro for convenient<br />BEGIN_RPC_IMP_INTERFACE(SampleRPC_Imp1, AsyncInterface)<br />rpc_ret_t get_val(rpc_in<int> x)<br />{<br />std::cout << "AsyncInterface::get_val(rpc_in<int> x=" << x.r << ")/n";<br />return x.r;<br />}<br />rpc_ret_t get_len(const std::string& x)<br />{<br />std::cout << "AsyncInterface::get_len(const std::string& x=/"" << x << "/")/n";<br />return x.size();<br />}<br />rpc_ret_t squareVec(vint_vec& x)<br />{<br />for (vint_vec::iterator i = x.begin(); i != x.end(); ++i)<br />{<br />*i *= *i;<br />}<br />return x.size();<br />}<br />rpc_ret_t multiVec(vint_vec& z, vint_vec& x, vint_vec& y)<br />{<br />z.clear();<br />for (int i = 0; i != x.size(); ++i)<br />{<br />z.push_back(x[i] * y[i]);<br />}<br />return 0x12345678;<br />}<br />END_RPC_IMP_INTERFACE()</p><p>// don't use macro for more control<br />class SampleRPC_Imp2 : public SampleRPC_Interface2<br />{<br />rpc_ret_t get_val(rpc_in<int> x)<br />{<br />std::cout << BOOST_CURRENT_FUNCTION << "x=" <<x.r << "/n";<br />return x.r;<br />}<br />rpc_ret_t get_len(const std::string& x)<br />{<br />std::cout << BOOST_CURRENT_FUNCTION << "x=" << x << "/n";<br />return x.size();<br />}<br />public:<br />// if use macro, such as SampleRPC_Imp1, app can not use custom create<br />static remote_object* create()<br />{<br />SampleRPC_Imp2* p = new SampleRPC_Imp2;<br />// set p<br />//<br />return p;<br />}<br />};</p><p>int main0(int argc, char* argv[])<br />{<br />try {<br />SocketAcceptor acceptor("0.0.0.0:8001");<br />rpc_server<PortableDataInput, PortableDataOutput> server(&acceptor);</p><p>// register rpc implementation class...<br />RPC_SERVER_AUTO_CREATE(server, SampleRPC_Imp1);<br />server.auto_create((SampleRPC_Imp2*)0, &SampleRPC_Imp2::create);</p><p>server.start();<br />}<br />catch (const std::exception& exp)<br />{<br />printf("exception: what=%s/n", exp.what());<br />}<br />return 0;<br />}</p><p>int main(int argc, char* argv[])<br />{<br />#if defined(_WIN32) || defined(_WIN64)<br />WSADATA information;<br />WSAStartup(MAKEWORD(2, 2), &information);<br />int ret = main0(argc, argv);<br />WSACleanup();<br />return ret;<br />#else<br />return main0(argc, argv);<br />#endif<br />}</p><p>

 

主要思路就是在 Server 端,用宏產生函式宣告和工廠代碼,把類註冊到工廠中,啟動server後,就可以自動接收client端的函數調用了。client發來的函數調用請求會派發到server端的使用者定義函數體。當然,client端沒有使用者定義的函數體。

在client端,同樣名字的宏,產生了和server端不同的代碼,這些代碼產生stub函數,把函數調用的參數序列化到網路。

其中主要使用了boost::tuple,和 boost::any,來產生stub的虛函數。

這個實驗很有趣,它說明了C++強大的表達能力,即使沒有IDL,僅使用語言本身就可以實現RPC。

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.