[C/C++/JAVA] Socket Communication Between JAVA and C/C++

  • Socket Communication Between JAVA and C/C++
  • Download: Java_C_Comm.zip

    最近需要讓多個不同的語言互相溝通傳輸,所以我採用的Socket做為通訊的基礎,在這一篇裡我們以Java Socket和C Socket為例,而Java與C的通訊概念跟這一篇[C/C++] Socket Connection是一樣的,只是要注意的是你所傳送的型態會不會有little/big endian的問題,以及各語言函式所判定的結束字元。

    對Java設計者而言,Java提供了ServerSocket和Socket這兩個類別,設計者只需要import java.net使用這兩個類別就可以完成Server-Client的設計。

    對C/C++設計者而言,如果不使用已經封裝好的Socket API,多半是使用Unix Socket的基礎來堆出一個Server-Client的程式,自然會比Java困難許多。

    這裡為了照顧兩個平台的使用者,我將C語言的Socket部份同時使用Unix Socket以及WinSocket來完成,並且以Java Socket的OOP概念將他們封裝成Server與Client類別。

    /*** Server類別定義如下:***/

    class Server{
    public:
    Server(const int port);
    ~Server();

    #ifdef _WIN32
    bool initWsa();
    #endif

    bool create();
    bool bind(const int port);
    bool listen();
    SOCKET accept();

    bool isValid() const;

    void close();
    private:
    int state;
    SOCKET socket;
    };

    多數人會將accept後的socket存放在Server的類別裡,這樣的定義很不好,因為Server類別裡不應該去實做send(), recv()這兩個輸出輸入的成員函式,因為Server最主要的功用就是監聽並建立連線。

    /*** Client 類別定義如下: ***/

    class Client{
    public:
    Client(){};
    Client(const char* ip, const int port);
    ~Client();

    #ifdef _WIN32
    bool initWsa();
    #endif

    bool create();
    bool connect(const char* ip, const int port);

    int send(const char* buf) const;
    int recv(char* buf);

    bool isValid() const;

    int operator = (SOCKET socket);
    int operator << (const char* buf) const;
    int operator >> (char* buf);

    void close();

    private:
    int state;
    SOCKET socket;
    };

    其中的operator = 的overload是為了給為Server socket做accept用的。

    兩個程式片段有些地方重複,為什麼不先自訂一個Socket類別,然後讓兩個類別都去繼承Socket?如同前面所提的,Server是不應該去實做send(), recv() ,所以扣掉這些,這兩個類別相同之處就更少了,我是覺得沒有必要讓他們都去繼承Socket類別。

    程式有不少地方仍保留C型態,且例外處理做的不完全,還請包含。

    說了這麼多都還沒提到這篇的重點,Java跟C通訊的關鍵,下面以C做為Server,Java做為Client互相傳送的程式碼。

    關於Winsocket的設計者而言,必須要小心處理WSA的問題,所以我將WSA清除的部份放在deconstructor裡,直到物件被釋放時才清除WSA,這樣做是為了方便Server端去關閉Client端連線,而不造成Server的WSA也被清掉。

    如果覺得光看解說難以懂,那你就下載原始碼慢慢看吧!

    /*** C Socket ***/

    client.send("Hello! I'm C++ Server.\n");
    client.recv(buf);

    /*** Java Socket ***/

    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    buf = in.readLine();
    PrintStream out = new PrintStream(socket.getOutputStream());
    out.print("Hello! I'm Java Client.\n");

    c socket的部份跟之前範例的使用方式是完全一樣的,只是在傳送的結尾我們要加上\n,因為在Java接收的那一端是以readLine()為基準,所以如果沒有跳行字元\n, Java那一端會繼續阻塞,直到對方連線中斷為止。當字串送達Java那一端之後,換行字元會被去掉,所以在列出console時還是要使用換行列出。

    所以簡單的Java與C的通訊該念就只有上面這麼一點,不管是什麼語言的互通,盡量以byte字元基準來傳送,比較不會送達到另一端語言接收後與原先不同的情形發生,但如果是比較複雜的編碼部份,有機會碰到我再補上來吧!

  • 編譯:
  • Linux 用戶:

    C語言部份我使用g++,Java部份我使用gcj,所以編譯之前請先裝這兩個編譯器。

    編譯方式如下:

    全部編譯:

    make -f makefile.gcc

    只編譯c++部份:

    make -f makefile.gcc cpp

    只編譯Java部份:

    make -f makefile.gcc java

    如果你還要使用的更細節的編譯部份,那你直接參考makefile.gcc的設定。

    Window 用戶(不保證能正常):

    C語言部份我使用mingw-g++,Java部份我使用mingw-gcj

    編譯方式如下:

    全部編譯:

    make -f makefile.mingw

    只編譯c++:

    make -f makefile.mingw cpp

    只編譯java:

    make -f makefile.mingw jav

    至於為什麼java的編譯方式是使用jav,而不是使用java,我也不知道mingw的make是怎麼了,我用java他總是給我說up to date,也就是一直不給我編譯。

    Java的部份其實我一直都不是很推薦使用gcj來編譯,但是這裡只是單純為了方便,且程式也很小,所以就將就一下。不然我比較推薦eclipse。

    為了要讓windows平台下能夠運作,花了不少時間在編譯設定上面,相關的套件可以參考這一篇[GCC] GCC for Windows (MinGW/DEV-C++)

  • 範例畫面:
  • Server : C++

    Client : Java

    /*** Server ***/

    /*** Client ***/

    當然上面是一個很簡單的範例,未來再繼續增加複雜的結構啦!

No comments:

Post a Comment

Orange - data analysis tool

Installation pip install orange3 Run orange python -m Orange.canvas