1. gzyueqian
      13352868059
      首頁 > 新聞中心 > > 正文

      淺談Java中通信機制及與C/C++ API的集成

      更新時間: 2007-12-21 09:01:07來源: 粵嵌教育瀏覽量:951

      背景:


        對于舊有系統(tǒng)的改造和升級,苦惱的莫過于跨平臺,跨語言。我的一個朋友近從Java專向了專攻.NET??因為.NET的CLR既有類似Java虛擬機概念這種已經(jīng)被證明很成功的底層托管能力。又對于Windows的就有桌面應(yīng)用提供了良好的兼容。


        近我的一個個人項目也面臨著這樣的需求。一個C語言開發(fā)的中間件,通過API暴露給二次開發(fā)及插件應(yīng)用。現(xiàn)在由于對其應(yīng)用的需求變得日趨復(fù)雜,而且正在脫離Unix的管理環(huán)境,走向基于JWS這樣的BCS管理。有朋友推薦我用JNI,但這樣一是增加了耦合度,二是讓Java睡在JNI感覺不太安穩(wěn)。在認知了上下兩層的系統(tǒng)平臺后,問題變得明朗起來:如何在HTTP協(xié)議下實現(xiàn)Java和C之間的交互?


      思路:


        本人對Java比較熟悉,先從Java的角度入手,Java間的通信方法:
        1 通過URL,Applet/JWS訪問被影射到URL的動態(tài)資源(Servlet)
        2 通過URL,Applet/JWS訪問共享的靜態(tài)資源(Server定期更新靜態(tài)資源)
        3 通過序列化和反序列化,實現(xiàn)簡單對象的傳輸(比如Resin的Hessian框架就提供了這種通信的方式)
        4 通過一些工具做代碼生成,利用Web Services實現(xiàn)客戶端和服務(wù)端的交互
        此外脫離HTTP,還可以做RMI,socket編程

        現(xiàn)在問題是通信的一端由Java變成了C/C++, 于是, 解決方案1需要把動態(tài)資源由CGI來定義,而方案3變得不再適用。于是方案有:
        1 通過URL,Applet/JWS訪問被影射到URL的動態(tài)資源(CGI)
        2 通過URL,Applet/JWS訪問共享的靜態(tài)資源(Server定期更新靜態(tài)資源)
        3 通過一些工具做代碼生成,利用Web Services實現(xiàn)客戶端和服務(wù)端的交互(×××這是我們討論的重點×××)

      解決方案:


        現(xiàn)在針對上文提出的3中通信方式中的1和3談一談實現(xiàn)的方法,2的實現(xiàn)方案比較靈活,需要發(fā)揮大家的想象力了:)


        針對CGI:
        首先CGI可以配置在各種主流的服務(wù)器中作為后端的腳本運行。大家可能對Servlet更熟悉一些。


        CGI可以用腳本寫,也可以用C來實現(xiàn)。CGI被觸發(fā)后,通過系統(tǒng)的環(huán)境變量來獲得輸入,在處理完畢后向標(biāo)準(zhǔn)輸出中輸出結(jié)果。


        由此可以想見,Web服務(wù)器在接受到來自HTTP協(xié)議的請求后,首先把請求的參數(shù)獲取到,然后設(shè)置到環(huán)境變量里。


        根據(jù)對訪問的URL的解析和服務(wù)器自身的配置,找到服務(wù)于請求的CGI程序的位置,然后執(zhí)行這個程序。


        這個程序被執(zhí)行后通過環(huán)境變量得到了服務(wù)器先前設(shè)置在環(huán)境變量中的參數(shù)。在經(jīng)過一些復(fù)雜的邏輯操作后,向標(biāo)準(zhǔn)輸出輸出結(jié)果。


        這個輸出又被Web服務(wù)器所捕獲,轉(zhuǎn)而傳遞回請求的客戶端。
        更多關(guān)于CGI的知識和理解,大家可以通過google來尋找答案

        上述CGI的方式可以讓我們直接獲取到結(jié)果,但是方案比較原始和基礎(chǔ)。其缺點有:


        1 需要自己制定類型傳輸協(xié)議,做封裝和拆封,否則只支持字符串
        2 我們不會為了要用C的API就給它裝一個或者自己實現(xiàn)一個Web服務(wù)器的,這讓我們的底層程序顯得蠢笨而冗余。我們希望能有一個超薄的Server外殼,


        在對API封裝后,通過某個端口進行開放即可。

        針對Web Servcies:
        Based on上面的兩個不足,我們只能把希望寄托在Web Services身上了,
        筆者在這里推薦給大家的是在C/C++很的Web Services工具gSOAP。大家可以到http://gsoap2.sourceforge.net/上去下載這個工具。


        通過這個工具,我們可以做到:
        1 一個Stand-alone的服務(wù)器外殼
        2 一個根據(jù)API程序自動生成的Web Services服務(wù)
        3 一個WSDL描述符文件

        下面說明有關(guān)基于gSOAP的Web Services C服務(wù)端和Java客戶端的運行機理,及通過Java客戶端訪問gSOAP的Web   Services的過程中需要注意的問題。

        客戶根據(jù) WSDL 描述文檔,會生成一個 SOAP 請求消息。Web Services 都是放在Web服務(wù)器后面,客戶生成的SOAP請求會被嵌入在一個HTTP POST請求中,發(fā)送到 Web 服務(wù)器來。Web 服務(wù)器再把這些請求轉(zhuǎn)發(fā)給 Web Services 請求處理器。請求處理器的作用在于,解析收到的 SOAP 請求,調(diào)用 Web Services,然后再生成相應(yīng)的 SOAP 應(yīng)答。Web 服務(wù)器得到 SOAP 應(yīng)答后,會再通過 HTTP應(yīng)答的方式把信息送回到客戶端。


        WSDL是Web服務(wù)中客戶端和服務(wù)端溝通的橋梁,描述了對象提供的方法。SOAP幫我們制定了一份被官方認可的對象的封裝方法。有了WSDL,客戶端只關(guān)心如何把參數(shù)用Soap封裝起來發(fā)出去,并獲取結(jié)果。服務(wù)端只關(guān)心如何對Soap進行拆包->服務(wù)->封包。gSOAP可以幫我們實現(xiàn)上述過程中的拆包和封包,而我們可以只關(guān)心服務(wù)的實現(xiàn)。

        言歸正傳,在這里我們以一個簡單的實現(xiàn)加、減、開放的Web Services的服務(wù)為例子,介紹gSOAP的使用:


        為了發(fā)布這個Web服務(wù),首先我們需要把服務(wù)的接口定義好,這個服務(wù)可能是一個現(xiàn)有服務(wù)的Adapter,為此我們定義頭文件
        calc.h:

        代碼

        typedef double xsd__double;
        int ns__add(xsd__double a, xsd__double b, xsd__double &result);
        int ns__sub(xsd__double a, xsd__double b, xsd__double &result);
        int ns__sqrt(xsd__double a, xsd__double &result);

        注意到這里面我們把double定義成了xsd__double(兩個下劃線),這是為了告訴gSOAP,我們需要的soap格式和WSDL格式是基于Document/literal的而非rpc/encoded.為了不把事情搞復(fù)雜,在這里我只能說,Java1.6自帶的Web Services工具只支持Document/literal格式的WSDL,所以我們生成這種格式的WSDL。
        編寫好頭文件后,我們就可以利用gSOAP提供的工具進行生成了:
        /usr/lib/gsoap-2.7/bin/soapcpp2 -S -2 calc.h
        生成的主要文件詳見附件。
        下面我們實現(xiàn)calc.h中定義的函數(shù):

        代碼

        // Contents of file "calc.cpp":
        #include "soapH.h"
        #include "ns.nsmap"
        #include
        int main()
        {
        struct soap soap;
        int m, s; // master and slave sockets
        soap_init(&soap);
        m = soap_bind(&soap, "localhost", 9999, 100);
        if (m < 0)
        soap_print_fault(&soap, stderr);
        else
        {
        fprintf(stderr, "Socket connection successful: master socket = %d\n", m);
        for (int i = 1; ; i++)
        {
        s = soap_accept(&soap);
        if (s < 0)
        {
        soap_print_fault(&soap, stderr);
        break;
        }
        fprintf(stderr, "%d: accepted connection from IP=%d.%d.%d.%d socket=%d", i,
        (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >>< img src="/images/forum/smiles/icon_cool.gif"/>&0xFF,  soap.ip&0xFF, s);
        if (soap_serve(&soap) != SOAP_OK) // process RPC request
        soap_print_fault(&soap, stderr); // print error
        fprintf(stderr, "request served\n");
        soap_destroy(&soap); // clean up class instances
        soap_end(&soap); // clean up everything and close socket
        }
        }
        soap_done(&soap); // close master socket and detach environment
        }
        // Implementation of the "add" remote method:
        int ns__add(struct soap *soap, double a, double b, double &result)
        {
        result = a + b;
        return SOAP_OK;
        }
        // Implementation of the "sub" remote method:
        int ns__sub(struct soap *soap, double a, double b, double &result)
        {
        result = a - b;
        return SOAP_OK;
        }
        // Implementation of the "sqrt" remote method:
        int ns__sqrt(struct soap *soap, double a, double &result)
        {
        if (a >= 0)
        {
        result = sqrt(a);
        return SOAP_OK;
        }
        else
        {
        return soap_sender_fault(soap, "Square root of negative value", "I can only compute the square root of a non-negative value");
        }
        }

        前文提到過,我們不希望為了發(fā)布基于Web Services的C語言的API而開發(fā)或應(yīng)用一個大的Web服務(wù)器。我們代碼中的main函數(shù)實現(xiàn)了一個簡單的Web Server(基于Socket).這個Server利用gSOAP生成的API來提供針對SOAP的處理。


        下面我們把這個嵌入式的web server編譯,編譯的時候注意stdsoap2.cpp這個文件是從gSOAP包中拷貝而來,不是自動生成的,大家下載gSOAP后直接就能找到這個文件及其頭文件。


        g++ -o calcServer calc.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
        一個以Web Servers形式提供的C API誕生了。
        在server端執(zhí)行./calcServer

        下面討論如何用Java1.6的自帶工具生成一個客戶端stub:


        把gSOAP生成的WSDL拷貝到我們的Java開發(fā)環(huán)境中來,按照Web Services Server中定義的端口和服務(wù)器,配置參數(shù)生成客戶端Web Services代碼:
        /usr/lib/jvm/jdk1.6.0_03/bin/wsimport -extension -httpproxy:localhost:9999 -verbose ns.wsdl

        生成后,把這個環(huán)境添加到eclipse的編譯環(huán)境中來,然后在eclipse中建一個新的類:


        代碼

        class Test {
        public static void main(String args[]) {
        Service service = new Service();
        double h = service.getService().sub(20000, 1);
        System.out.println(h);
        }
        }


        運行后得到結(jié)果19999.0



      免費預(yù)約試聽課

      亚洲另类欧美综合久久图片区_亚洲中文字幕日产无码2020_欧美日本一区二区三区桃色视频_亚洲AⅤ天堂一区二区三区

      
      

      1. 亚洲国产欧美日韩欧美特级 | 伊人色综合久久天天小片 | 亚洲有码中文字幕 | 亚洲成aⅴ人影院在线观看 亚洲日韩久久精品中文字幕 | 亚洲AV秘一区二区三区 | 中文字幕v亚洲日本 |