Saturday, September 20, 2008

[C/C++] GNU Debuger - gdb

  • gdb
  • 平常使用gcc做為編譯器開發程式時,遇到segmentation fault多半是自行除錯,這裡可以使用gdb來縮短除錯的時間,以[C/C++] Stack Overflow這一篇的程式作為範例,編譯方式如下:

    gcc -g- o stackoverflow stackoverflow.c

    然後執行gdb並且附帶專案名稱:

    gdb stackoverflow

    接著你可以直接先執行run

    run

    你就會看到如下的錯誤:

    Starting program: /home/xinyu/Desktop/stackoverflow
    In main()...
    In func1()...

    Program received signal SIGSEGV, Segmentation fault.
    func2 () at stackoverflow.c:26
    26 printf("In func2()...\n");

    這時你可以使用break指令來設定break point

    break 20

    重新在執行一次run,就會在程式碼20行的位置停下來,你可以輸入下面的指令來看更多的gdb指令參數:

    help all

    離開gdb

    q

[UTips. 55] ufw & gufw

  • ufw & gufw
  • ubuntu 8.04有自帶ufw防火牆,但是預設情況下是沒有開啟的,你可以透過下面的指令啟動和關閉ufw:

    啟動ufw:

    sudo ufw enable

    關閉ufw

    sudo ufw disable

    顯示ufw的rule:

    sudo ufw status

    新增過濾規則:

    開啟ssh port

    sudo ufw allow ssh

    或者你可以這樣設定

    sudo ufw allow 22/tcp
    sudo ufw allow 22/udp

    限制某個IP不准連入ssh的話如下:

    sudo ufw deny from 192.168.2.10 to any port ssh

    允許整個網段連入ssh,如下:

    sudo ufw allow from 192.168.2.1/24 to any port ssh

    刪除規則跟新增規則雷同,只要在ufw後面接上delete,隨便舉上面任一個例子。

    sudo ufw delete deny from 192.168.2.10 to any port ssh

    如果你覺得上面的設定對你而言太折磨了,那你可以使用gufw來做設定,gufw是ufw的圖形介面版本,官方頁面如下:

    http://gufw.tuxfamily.org/index.html

    另外其實還有其他圖形化的防火牆,

    firestarter

    sudo apt-get install firestarter

    guarddog

    sudo apt-get install guarddog

    當然最正統的還是直接使用iptables

    https://help.ubuntu.com/community/IptablesHowTo


[UTips. 54] CUPS Server

  • CUPS Server
  • 要使用ubuntu作為印表機列印伺服器,除了可以安裝samba讓windows也能使用之外,你還可以使用CUPS來做相同的事情。安裝方式如下:

    sudo apt-get install cupsys cupsys-client cupsys-common

    安裝完畢之後,接著要設定cupsd.conf,路徑在/usr/cups/cupsd.conf。

    Listen 0.0.0.0:631
    [location /]
    Order allow,deny
    Allow From 192.168.1.2
    [/location]
    [location /admin]
    Order allow,deny
    Allow From 192.168.1.2
    [/location]
    [location /admin/conf]
    AuthType Default
    Require user @SYSTEM
    Order allow,deny
    Allow From 192.168.1.2
    [/location]

    本地端的連線允許設定,這裡是以192.168.1.2作為範例,請改成你自己的本機IP。設定完後重新啟動cupsys。

    sudo /etc/init.d/cupsys restart

    接著你就可以在網頁上輸入http://192.168.1.2:631進入Common Unix Printer System的頁面,確定你的本機印表機有在清單上,那就設定完畢了。

    如果你的printer是要分享給其他linux使用者,你必須做如下的設定。


  • Windows Client
  • 在windows底下使用Server上的印表機。

    控制台->印表機和傳真->新增印表機->網路印表機或連接到其它電腦的印表機->連線到網際網路、家用或公司網路上的印表機->http://xxx.xxx.xxx.xxx:631/printers/printer_ name。

    printer_name是你的印表機名稱,你可以從剛剛那個web頁面上查詢到。

    接著就是安裝驅動程式,設定完畢。

  • Linux Client
  • 一樣也是要執行System->Administration->Printing,然後做下面的設定

    確定之後,重新刷新頁面,應該就會看到印表機了。

    關於HP Printer的使用者,如果找不到合適的驅動程式,可以安裝下面的套件:

    sudo apt-get install hplip

Thursday, September 18, 2008

[UTips. 53] NX

  • NX
  • 在Linux底下常用的遠端連線方式除了有SSH, XDMCP, VNC之外,這裡推薦一個整合型的遠端連線程式- NX,是一套由NoMachine開發出來的工具,基本上是可以支援大部分的Linux平台,但是如果是Windows平台就不敢保證執行的穩定性了。

    NX Free Edition只提供2個User的上限以及2個concurrent的連線。

  • NX Server
  • 下載頁面如下:

    http://www.nomachine.com/download-package.php?Prod_Id=5

    分別將nxclient, nxnode以及nxserver下載至/usr目錄底下,並且解壓縮,解壓縮後所有檔案都會在/usr/NX這個目錄底下,執行下面的指令來安裝。

    sudo /usr/NX/scripts/setup/nxnode –-install
    sudo /usr/NX/scripts/setup/nxserver –-install

    如果你覺得上面的安裝是一種折磨,那你可以去下載.deb版的來安裝。

    安裝完畢後你可以到/usr/NX/bin執行下面的指令來檢查nxserver 是否啟動:

    sudo ./nxserver --status

    啟動nxserver:

    sudo ./nxserver --start

    關閉nxserver:

    sudo ./nxserver --stop

  • NX Client
  • Linux用戶:

    http://www.nomachine.com/download-client-linux.php

    一樣從官方下載linux版的nxclient,然後解壓縮至/usr/底下,將目錄切換至/usr/NX/bin,比且執行下面的指令:

    ./nxclient

    第一次執行他會跳出精靈畫面要你設定server的資訊,請依照你的系統規格去設定,解析畫面最好就使用1024x768。

    至於登入的帳號密碼就是你要連線的server上的帳號密碼。

    如果你有多個連線要設定,那你可以使用下面的指令去產生更多session:

    ./nxclient --wizard

    如果你需要一個圖形介面去管理多個session時可以執行下面的指令:

    ./nxclient --admin

    第一次連線會比較久一點,因為要建立session然後要交換key跟做驗證,自然會比沒有通訊加密的VNC來的久一點,但是在操作過程中畫面比VNC還要來的順暢。你可以自訂顯示設定,讓效能更好一點。

    Windows用戶:

    http://www.nomachine.com/download-client-windows.php

    下載完後,安裝完畢,操作方式大部分跟Linux的Client是一樣的,只是在強調一次,使用windows來連線很有可能出現無法預期的狀況。

    更詳細的資料可以參考官方的說明文件:

    http://www.nomachine.com/documents.php

  • server.cfg設定 (非必要)
  • 編輯下面的檔案:

    sudo nano /usr/NX/etc/server.cfg

    設定下列的值,把前面的#字號拿掉:

    EnableUnencryptedSession = "0"
    EnableClipboard = "both"
    EnableUserDB = "1"
    EnablePasswordDB = "1"

    從上到下分別為"只使用安全加密傳輸","開啟剪貼簿分享","限制僅能給nx 用戶登入","限制nx 用戶的密碼設定"。

    multi-node為Advanced Server才有的功能,所以相關的設定就不要打開啦!不然你只會看到一堆錯誤。

  • 新稱nx 用戶(非必要)
  • 設定完server.cfg之後,你可以透過下面的指令新增用戶:

    sudo ./nxserver --useradd nx_test_user --system

    其中nx_test_user就是用戶名稱,而加上--system識別,他會幫你建立家目錄,並且詢問你給予這個帳號的密碼。

    新增完畢我們來重新啟動一下nxserver,就可以使用nxclient做連線了。

    雖然server.cfg跟新增nx user並不是必要的動作,但是我還是滿推薦大家去設定,畢竟會比較安全一點。

  • 刪除用戶(補充)
  • 使用下面的指令來刪除帳號:

    ./nxserver --userdel nx_test_user --system

    如果你的nx user出現怪問題,請先確定你是否正常刪除帳號,否則只好重新申請過別的帳號。

    如果你只是要做近端網路的操控且又不想用NX的話,那你可以參考這一篇的VNC設定。

    UTips. 47: VNC Server

Sunday, September 14, 2008

[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 ***/

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

Tuesday, September 09, 2008

[UTips. 52] ntpd

  • ntpd
  • 最近不知道怎麼搞的系統時間總是不準,為了校正時間只好裝了ntpd(Network Time Protocol (NTP) daemon),一般用戶是不太需要安裝此daemon,因為通常Server才需要比較精準的時間。

    sudo apt-get install ntp

    台灣時區的使用者可以用下面的設定來更新ntp server:

    ntpdate tw.pool.ntp.org

    其他時區的使用者可以參考下面的網頁。

[C/C++] Process Monitor for Window

  • Process Monitor for Window
  • Download: ProcessMonitor_w32.zip

    這是一支當時在windows底下設計程式的時候所寫的一個小工具,因為不想人工盯著螢幕觀察,所以使用了psapi來設計一個可以監控特定的process的記憶體使用狀態。

    程式是以Process的名稱來作為辨識(實際上還是以PID為主),但是有時候同一個時間會有兩個以上同名的Process,所以應該要有一個功能依照PID來做輸入依據才對(這個功能可以用我裡面的PrintProcessNameAndID()來完成,因為正常情況下使用者無法在Windows環境底下得知某個程式的PID,所以你無法要使用者去輸入PID,必須先列清單給他選則)。

    程式以每三秒紀錄一次,在所要監控的程式結束之後會將紀錄存在log.txt檔裡。(但是如果pm.exe本身自行中斷,那就沒有紀錄檔,這部份可能需要使用process programming的技巧去判斷程式的中斷來做處理。)。

    裡面的字串使用的是TCHAR,因為當初是在Visual C++ 2005上開發,所以理論上程式複製到visual c++ 上是可以跑的,只是別忘了設定一下psapi.lib這個library。

    因為我對TCHAR不是很熟悉,所以自己做了一個_tstrcmp()來符合TCHAR這個字串的格式。

    當時能力有限,寫的不好還請包含。

[Gtk] Gtk Go/Reversi Board Template

  • Gtk Go/Reversi Board Template
  • Download : GtkGoBoard.zip

    Download : GtkReversiBoard.zip

    要實現板子遊戲的介面多半是使用數個按鈕元件(排列成矩陣的方式)來完成,但是如果版子上的物件一複雜(例如西洋棋),那這個時候使用DrawingArea會是一個比較好的解決方式(畢竟Gtk跟Gimp可是有密切的關係)。這裡提供使用Gtk的DrawingArea畫出的圍棋以及黑白棋的板子樣板程式,有興趣的人拿去玩玩看吧!(左鍵:黑棋,右鍵:白棋,中鍵:取消)

    Gtk Go Board Template:


    Gtk Reversi Board Template

    基本上板子的大小部份都處理好,美中不足的是棋子的大小我沒有讓它動態變更,有時間我再補強吧!

    PS. 記住!這是樣板,沒有 AI。

[wxWidget] wxWidget & wxFormBuilder

  • wxWidget & wxFormBuilder
  • 如果你會使用Qt,那wxWidget就更容易上手了,官方下載頁面:

    http://www.wxwidgets.org/downloads/

    安裝方式如下:

    Linux用戶

    • mkdir build_gtk
    • cd build_gtk
    • ../configure
    • make
    • sudo make install
    • sudo ldconfig

    裝完後你就可以透過下面的方式來編譯wxWidget的程式。(假設你的程式叫做main.cpp)

    • g++ -o main main.cpp `wx-config --libs --cxxflags`

    上面的編譯方式跟Gtk很像。

    撰寫過程中你會大量參閱官方的說明文件(比起Qt的官方文件,wxWidget似乎比較難閱讀)

    http://docs.wxwidgets.org/stable/

    為了加速開發的效率,所以我選擇了wxFormBuilder來作為輔助,官方下載如下:

    http://wxformbuilder.org/?page_id=7

    ubuntu用戶可以直接使用下面的指令安裝:

    • sudo apt-get install wxFormBuilder

    如上圖,跟一般的GUI Designer沒有什麼差別,只是不管是Gtk的glade, Qt的Designer或者是wxWidget的wxFormBuilder,他們給我的共通點都是預覽視窗的排版和大小總是和編譯後的差很多,所以往往我都會選擇直接hand-coding。

    wxFormBuilder Tutorials

    http://wiki.wxformbuilder.org/Tutorials/UsingWxFormBuilder

    下面是一個簡單的範例,整合之前在Gtk實做的Randomly Password Generator以及在Qt裡實做Password Security Checking。

    Download: wxPassApp.zip

    上半部是檢查密碼安全度,下半部是產生密碼,為了配合Gauge元件,檢查密碼的演算又在改了一些。

    程式主要的關鍵有兩點。

    • hierarchy structrue :簡單來說就是用繼承的方式來撰寫,Password繼承於PassForm,PassForm繼承於wxFrame,把核心GUI程式碼包在PassForm裡,而關鍵的Events則以virtual fucntion的形式讓derived class去實做。程式主要演算則是包在Password這個類別裡(或者可以用hasA的方式去繼承其他類別),如此一來每次修改ui後,交給wxFormBuilder去更新PassForm.cpp PassForm.h即可(如果大幅度修改還是得手動修正一下程式碼會比較好。)
    • wxString to char* : 跟Qt一樣,wxWidget有自己定義好的string類別-wxString,所以如果要使用傳統的ascii型態的char,勢必要轉換一下才行。

    Windows用戶:

    Download: wxPassApp_mingw.zip

    自行在windows裡編譯wxWidget空間耗用很大,所以直接裝打包好的wxDev-C++會快一點,wxDev-Cpp已經將對應給MinGW和Visual C++的library和include處理好,直接使用即可。比較不解的是wxDevCpp本身就是以GCC 3.42為主要的compiler,但是我在測試編譯過程中出現[Linker error] undefined reference to `__cpu_features_init',還是得加上MinGW的library,你可以直接使用我的範例檔裡的makefile,大致上該有的都設定好了。

    關於MinGW和wxDev-Cpp的安裝方式可以參考這一篇:

    [GCC] GCC for Windows (MinGW/DEV-C++)

Monday, September 01, 2008

[Gtk] Gtk for Windows

  • Gtk for Windows
  • Gtk本身是個跨平台的視窗設計API,你可以到官方下載windows版的Gtk:

    http://ftp.gnome.org/pub/gnome/binaries/win32/gtk+/2.12/

    下載完後解壓縮到你想放的目錄底下,筆者我放在C:\底下,接著要設定環境變數,將Gtk的bin目錄資料夾位置設定到PATH裡,(例如我的路徑在C:\gtk+-bundle-2.12.11\bin),如此你就設定完Gtk了,如果你還沒裝上MinGW,你可以參考這一篇的設定[GCC] GCC for Windows (MinGW/DEV-C++)

    使用沒有與glade結合的原始碼做為範例(因為目前為止筆者我還不知道如何讓windows也能使用glade)

    Download: GGenPass.c

    如果你先編譯了話,你會發現不能編譯,因為windows會跟你說找不到$#^%$&%,這時只好自行手動設定makefile裡的library和include位址,我的makefile內容如下:

    ########### makefile start ###############

    CC = gcc
    LIBS = -LC:/gtk+-bundle-2.12.11/lib -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangowin32-1.0 -lgdi32 -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lintl
    INC = -mms-bitfields -IC:/gtk+-bundle-2.12.11/include/gtk-2.0 -IC:/gtk+-bundle-2.12.11/lib/gtk-2.0/include -IC:/gtk+-bundle-2.12.11/include/atk-1.0 -IC:/gtk+-bundle-2.12.11/include/cairo -IC:/gtk+-bundle-2.12.11/include/pango-1.0 -IC:/gtk+-bundle-2.12.11/include/glib-2.0 -IC:/gtk+-bundle-2.12.11/lib/glib-2.0/include -IC:/gtk+-bundle-2.12.11/include/libpng12
    CFLAG = -c -Wall -g
    BIN = GGenPass.exe
    OBJS = GGenPass.o

    all: $(OBJS)
    $(CC) $(OBJS) -o $(BIN) $(LIBS)


    GGenPass.o: GGenPass.c
    $(CC) $(CFLAG) GGenPass.c $(INC)

    clean:
    del /Q/F *.o *.exe

    ############# makefile end ##############

    當然那些路徑並不是我一個字一個字打上去,是用I/O重新導向輸出完成的,如下:

    • pkg-config --cflags --libs gtk+-2.0 >inclib.txt

    上面的指令就會把Gtk相關的library和include路徑輸出到inclib.txt檔案裡

    至於上面程式的編譯結果跟上一篇是一樣的,只是界面醜了點,所以Windows底下沒有特別需求,還是使用C#吧!