[C/C++] Socket Programming: Upload/Download

  • Socket Programming: Upload/Download
  • Download:upload_download_unix.zip

    繼上一篇[C/C++] Socket Connection我們將scoket connection延伸應用至檔案傳輸。流程圖如下:

    這個範裡我只實做upload和download兩個功能,為了要處理Nagle's algorithm所帶來的影響,所以我的程式實做方式會有點不同。其中主要的程式片段是在檔案下上傳的部份,如下:

    /*** Server.c in upload() ***/

    /* Send file data to client */
    do{
    memset(buffer, '\0', BUFF_SIZE+1);
    ret = fread(&buffer, sizeof(char), BUFF_SIZE, fp);
    ret = send(socket, buffer, ret, 0);
    if(ret == -1){
    fprintf(stderr, "Fail to send message to client\n");
    return 0;
    }
    }while((count += ret) < totalSize);

    /*** Client.c in upload() ***/

    /* Send file data to server */
    do{
    memset(buffer, '\0', BUFF_SIZE+1);
    ret = fread(&buffer, sizeof(char), BUFF_SIZE, fp);
    ret = send(socket, buffer, ret, 0);
    if(ret == -1){
    fprintf(stderr, "Fail to send message to server\n");
    return 0;
    }
    usleep(1000);
    fprintf(stderr, "\b\b\b\b\b\b\b%c%6.2f", 37, (double)((count+ret) * 100 / totalSize));
    }while((count += ret) < totalSize);

    ret為整數變數,用來承接所有接收到的大小,在這次的修正版裡全部的send(), recv()都以BUFF_SIZE為基礎,唯只有在檔案傳送的部份則是以fread()回傳數來決定。

    由於在遠端傳輸過程中並不像近端網路下的理想對等,所以在接收過程中我以檔案的總大小(totalSize)與目前接收的量做為是否繼續接收資料的依據。

    此版本是以Linux系統為基礎修正了一些之前沒有做的錯誤處理,並使用fork來作多人連線的功能,關於fork()的使用可以參考這一篇[C/C++] Process Programming - fork(),或者你也可以使用pthread來完成[C/C++] Multithreading Porgramming - pthread

[C/C++] Socket Connection

  • Socket Connection
  • 節錄自筆者的Network Programming其中的資料,一般在Windows底下如果要寫網路程式多半會想到Microsoft MFC提供的相關API,而Linux底下則多使用Unix Socket來實現,這裡筆者要簡短的介紹如何使用最基礎的socket函式來實做socket connection。

    在正式進入程式碼之前還是要先簡單了解一下基本的OSI Model。

    只是想要藉由這張圖來讓讀者知道我們現在做的部份是在OSI七層中的最上層-應用層。有了上面的簡單概念後我們可以開始來看程式碼了。

    Download:Server.c

    Download:Client.c

    這是一個主從式的架構(Server-Client),為了讓程式碼可以在Linux以及Windows上運行,特別針對這兩個平台來撰寫。我們先來看一下流程圖。

    其中Initial WSA這個部份是Windows才需要的,其餘兩個平台都可適用。

    ########Server Side (Server.c) ###########

    • Library
    • 以Windows Socket來說,我們使用了winsock1.1來實做,而unix部份則是一般的unix socket。

    • Init WSA
    • 如同前面所提,Windows Socket需要初始化WSA才能使用。

    • Create a Socket
    • 建立一個Socket,其中比較重要的是SOCK_STREAM,定義這個socket是以stream的型態來傳輸,另外還有raw,datagram等型態,您可以自行查閱網路。

    • Setup Address & Port
    • 設定IP跟Port的部份其實很直觀,只是在型態的部份可能會讓讀者很困惑。

    • Bind Socket
    • 將socket server跟sockaddr in給bind起來,如此才能傳送接收訊息。也許你會問為什麼還要這麼麻煩做那麼多事情,別忘了這裡是socket最低階的寫法,自然什麼事情都要自己來啦!

    • Listener
    • 監聽Client端的連線,其中10是最大Quene值,代表著同時間可以有10個人在等待連線。

    • Wait for Accepting
    • 等待Client端做確認才完成一個socket連線

    • Close Socket
    • 如同開檔關檔一樣,使用完連線請關閉它。

    ########### Client Side (Client.c) #############

    如果你看得懂Server的部份,那Client就更沒問題了,Client的部份很簡單,只是建立一個Socket然後去對Server做連線

    只是不要忘了Client端的IP設定要設成Server的IP(不然你要連去哪裡?),既然是要去連Server那當然是用Connect()函式,重點只有這個部份,連線完後也記得關閉檔案。

    透過上面的簡單Server-Client的連線範例你就可以寫出許多網路連線程式了。

    編譯方式:

    GCC:

    • gcc -o server server.c
    • gcc -o client client.c

    MinGW:

    • gcc -o server server.c -lwsock32
    • gcc -o client client.c -lwsock32

    這裡特別說明MinGW的部份,雖然MinGW是適用於Windows底下的GCC,但是library的部份還是得要使用由MinGW所提供的才能編譯,wsock32是winsocket 1.1,而ws2_32是winsocket2.0的library。

    程式一開始的定義載入了wsock32.lib那是給Visual C++使用的,所以同樣的你也可以直接複製上面的程式碼到Visual C++去編譯成Console程式。

    參考資料:

    關於Unix Socket設計的部份我很推薦下面的資料

    除此之外,有時間的話也可以參考Linux System Programming的 I/O部份,有助於了解socket通訊的底層概念。

    另外還有微軟的MSDN裡的WinSocket資訊:

    http://msdn.microsoft.com/en-us/library/ms740673(VS.85).aspx

    以及IBM的i5/OS Communication的部份:

    http://publib.boulder.ibm.com/infocenter/iseries/v5r4/index.jsp?topic=/rzab6/rzab6soxoverview.htm

    如果你需要將c socket的部份封裝成C++的形式,下面是我將C Socket轉成C++的範例:

    Download: C++ Socket

    另外你還可以參考以下幾篇較進階的文章

    [C/C++] Socket Programming: Upload/Download

    [C/C++] Socket Programming: Get Ethernet Informati...

    [C/C++] Scoket Programming : Non-Blocking Communat...

    [C.C++] Socket Programming: MultiPerson Chat

Synapse - Papapaçoca

  • Synapse - Papapaçoca
  • 這是2007年Imagine cup ShortFlim決賽的影片,很喜歡設計者的思維,有興趣的人可以花個時間觀看。


[Perl] Words Separating

  • Words Separating
  • 有看過筆者[C/C++] Word Separating都知道文字處理如果要完全自行實做,那將會是...(嘔吐到死),在之前文章裡我刻意不用strtok()函式來自行實做單字分離,並且使用了linked-list型態以及相關的排序來完成,所以整體在撰寫上自然就有一定的複雜度存在。如果同樣的問題交給Perl來寫又會是怎樣的情形,程式碼如下:

    Download:sepWord.pl

    不要懷疑,程式碼就只有這樣,不到30行的Perl相當於上次寫了200多行的C,執行效率如何我們來測試一下。

    ### Perl : sepWord.pl ###

    #time ./sepWord.pl text PLspText 0

    real 0m0.018s

    user 0m0.008s

    sys 0m0.004s


    ### C: sepWord ###

    #time ./sepWord text CspText 0

    real 0m0.004s

    user 0m0.000s

    sys 0m0.004s

    在粗略的測試比較之下,這一類的程式比較結果是C語言比Perl快四倍,實際的效能差距僅供參考,因為這兩個語言筆者我並未對他們做最佳化,例如C語言的排序部份,編譯最佳化以及Perl的正規表示法部份都未用到最佳的狀態,但唯一可以確定的是,對一般的程式設計師而言,同樣的功能程式,用C可以換取較好的效能,用Perl可以減少較多的開發時間,究竟哪一個好,各取所需啦!

[Windows] Services Configuration

  • Services Configuration

    如果要快速的將Windows XP做效能最佳化,尤其是記憶體的空間方面時,那最主要的修改方向就是Services跟Startup這兩個部份,這裡我將我自己的設定列出來。在修改Servivces之前我強烈建議先做以下工作,尤其是不太了解系統者。

    • 做完整系統備份
    • 充分的了解自己的使用需求
    • 不確定的Service請設定為Manual

    一般情況下我們非常不建議使用者在不確定的情況下任意修改Services,雖然修改的方式很簡單,但是一般使用者比較不了解其相依性,有可能不知道要啟動哪些Services需要連帶啟動其他的Services,或者是哪天忽然要用到哪些功能,卻忘記自己關了對應的Services。

    這裡我將我自己的設定列出來,具有爭議性的Services我會特別加以說明。

    Disable Services:

    Alerter:

    ClipBook:

    Computer Browser: 如果你不需要使用網路芳鄰瀏覽其他電腦

    DHCP Client: 如果你不需要DHCP自動幫你找尋IP

    Distributed Transaction Coordinator:

    DNS Client:

    Error Reporting Service:

    Event Log:

    Fast User Switching Compatibility:

    Help and Support: 如果你不需要檢視說明與支援

    Human Interface Device Access:

    IMAPI CD-Burning COM Service: 如果不想使用內建燒錄功能

    Messenger:

    Print Spooler: 如果沒有印表機

    Remote Registry:

    Security Center: 如果不想要看到煩人的安全心中

    SSDP Discovery:

    System Event Notification:

    System Restore Service: 如果不想使用系統還原

    Task Scheduler: 如果不使用工作排程

    Telephony: 如果不使用撥接

    Telnet:

    Windows Firewall/Internet Connection Sharing(ICS): 如果不使用內建防火牆

    詳細的設定說明可以參考下面的網站資訊,有些網站所提供的服務建議設定太過最佳化,設定完之後效能提昇很多,到同時也失去了很多該有的功能,所以不厭其煩的提醒使用者設定之前要仔細一點。

    http://www.ss64.com/ntsyntax/services.html

    http://www.theeldergeek.com/services_guide.htm

[Windows] Batch Language

  • Batch Language
  • 或許有很多人認為Batch Language是原始人才用的語言,但是事實上許多windows管理員還是利用著Batch來完成許多事情,畢竟Batch裡面還是有許多不錯用的功能。在這一篇裡我會介紹一些筆者自己常用的範例。

  • Backup My Favorites
  • 平常要備份Favorites總要打開好幾層的資料夾然後複製到自己要存放的地方,這樣的工作如果一直重複做就變得很厭煩。這時我們就可以使用Batch Langauge來幫我們完成。

    將以下文字存成bakFav.bat檔

    rem. #### Backup My Faviorites ###############

    XCOPY "%USERPROFILE%\Favorites" "D:\backup\Favorites" /S /D /H

    rem. #################################

    這裡我們使用了XCOPY這個指令幫我們把profile底下的Favorites複製到我們指令的備份路徑,如果路徑不存在他會詢問你要不要建立。其中後面接著參數分別代表如下:

    /S: 備份目錄資料夾底所有子目錄及檔案

    /D: 差異備份

    /H: 備份隱藏跟系統檔

    至於我們為什麼要使用%USERPROFILE%而不使用C:\Document ans Settings\##@%@#的原因是因為如果只絕對路徑哪這個batch檔就無法通用了。

    另外常用的相對路徑指令如下:

    %temp% :C:\Documents and Settings\user\Local Settings\Temp

    %systemroot% :C:\WINDOWS

    %programfiles% :C:\Program Files

    光是這樣你可能還是會嫌每次還要點擊bakFav.bat是一件苦差事,如果我一下子要備份好多東西,那豈不是常常都要點這些batch file,你可以把這些batch file放在啟動(附屬應用程式>>啟動)裡或者使用使用排程(控制台>>工作排程)來幫我們每日備份或者其他時間備份。

  • Clean Files
  • 清除檔案的工作也可以交給Batch來做,尤其是要清除一些讓人覺得很厭煩的垃圾檔案,

    將以下的文字存檔成clean.bat

    rem. ####### Clean Files ###########
    @echo off
    IF "%1" =="" goto NONCMD

    del /F /Q /A %1:\*.sqm
    del /F /Q /A %1:\autoruns.inf
    goto :END

    :NONCMD
    set /p label=Enter a Drive Label:

    del /F /Q /A %label%:\*.sqm
    del /F /Q /A %label%:\autoruns.inf
    goto :END

    :END
    echo.Clean Completed!

    @echo on
    rem. ###############################

    上面就是一個比較標準的batch file範例,一開始跟結尾用了echo off/on只是要設定將中間的處理過程不要將所有的狀態都寫是在command line底下而已,其實你也可以不用這樣設定。

    %1對應著第一個參數,如果你在cmd底下這樣輸入clean c,那clean對應到%0,而c對應到%1,依此類推就會有%2,%3,%4......。

    IF內的比較運算還有(equ,neq,lss,leq,gtr,geq),通常我們都會搭配著goto來使用,要注意的是,如果我們要跳到END,那END的片段宣告必須是:END是要加上:這個符號的。

    del所接著參數解釋如下:

    /F:強制刪除唯獨檔

    /Q:寧靜模式

    /A:刪除系統檔,隱藏檔,唯獨檔等類型

    經由del刪除後是直接刪除,所以讀者在使用這些參數及del實務必要小心。

    多數人都懶得從cmd底下去執行batch file,所以在前面的指令我就先判斷使用者是否有接參數,如果沒有的話就要跳出提示視窗讓使用者輸入drive label,這部份就是由set /p label=Enter a Drive Label:來處理,這樣的功能也是可以適用在cmd底下的。

    你可以增加更多清除的項目,讓這個clean.bat更加完善。

  • List All Directories
  • rem.========== List All Dirs ===============

    dir /s /on /b /a:d > dir.txt
    FOR /F %%v IN (dir.txt) DO dir %%v > %%v/list.txt

    rem. ================================

    上面兩行指令可以讓每個子目錄下都建議一個目錄資料夾清單(list.txt).

    Batch Lauguage基本常用的就先介紹到這裡,更詳細的訊息你可以參考下面的網頁:

    MS-DOS/MSDOS Batch Files: Batch File Tutorial and Reference:

    DOS BATCH FILE TUTORIAL

UTips. 47: VNC Server

  • VNC Server
  • 平常在做一般的遠端連線時使用SSH已經很足夠,但如果想要操控圖形化介面,我們可能就需要用到VNC,Server端的安裝方式如下:

    sudo apt-get install vnc4server xinetd

    我們同時安裝了xinetd來取代傳統的inetd。

    啟動VNC之前我們要先開啟XDMCP

    sudo nano /etc/gdm/gdm.conf

    找到一行叫做RemoteGreeter=/usr/lib/gdm/gdmlogin前面的#拿掉。

    接著找到一個叫做[xdmcp]的字串,把他下面的Enable=false改成

    Enable=true

    再來我們要去設定xinetd,

    sudo gedit /etc/xinetd.d/Xvnc

    將以下的設定貼入到Xvnc裡

    service Xvnc
    {
    socket_type = stream
    protocol = tcp
    port = 5901
    wait = no
    user = nobody
    server = /usr/bin/Xvnc
    server_args = -inetd -query localhost -geometry 1024x768 -depth 16 -once -cc 3 -fp /usr/share/X11/fonts/misc
    }

    存檔後重新啟動Xinetd

    sudo /etc/init.d/xinted stop

    sudo killall Xvnc

    sudo /etc/init.d/xinetd start

    我們還要設定xstartup

    sudo nano ~/.vnc/xstartup

    將twm&前面加上#,然後最後面加上

    gnome-session &

    存檔後離開,最後我們還要為vnc設定登入密碼

    vncpasswd

    一切設定完畢,啟動vnc server

    vncserver

    或者你可以指定port啟動

    vncserver :1

    如果要關閉vncserver 可以這樣使用

    vncserver -kill :1

    如果出現error locking in .Xauthority的訊息,請先確定你的目錄下的 .Xauthority檔案權限是否設定正確。

UTips. 46: NFS Server

  • NFS Server
  • 如果今天是兩個linux系統要做分享時,我們就會用到NFS Server,安裝分別如下:

    Server:

    sudo apt-get install nfs-kernel-server nfs-common

    Client:

    sudo apt-get install nfs-common

    裝完後我們要設定要分享的檔案路徑以及權限

    sudo gedit /etc/exports

    假設我們的Server IP是192.168.2.10,要分享的路徑是/home/user/share,那我們的設定如下:

    /home *(rw,sync)

    如果你是希望只有192.168.2.5這個IP可以做連線的話,那你可以這樣設定

    /home 192.168.2.5(rw,sync)

    或者你要讓整個192.168.2的網域可以做連線,那你可以這樣設定

    /home 192.168.2.0/24(rw,sync)

    存檔後我們要執行以下指令來更新狀態

    sudo exportfs -ra

    然後重新啟動nfs server

    sudo /etc/init.d/nfs-kernel-server restart

    接著我們到Client端上打上如下的指令觀看Server上有提供哪些分享

    showmount -e 192.168.2.10

    或者你可以直接掛載Server上分享的目錄

    sudo mount -t nfs 192.168.2.10:/home/user/share /mnt/nfshare

    解掛載就跟一般情形一樣

    sudo umount /mnt/nfshare

    如果想要一開機就掛載,可以設定/etc/fstab如下:

    192.168.2.10:/home/user/share /mnt/nfshare nfs defaults 0 0


UTips. 45: Samba Server

  • Samba Server
  • 在Linux底下的進端網路與Windows溝通時,使用FTP固然是一個方法,但是我們還有更好的選擇,那就是Samba,安裝方式如下:

    sudo apt-get install samba

    裝完之後先把samba給停止。

    sudo /etc/init.d/samba stop

    我們必須先做一些設定。

    sudo nano /etc/smaba/smb.conf

    找到;security = user,將;這個符號給去掉,意思是我們要開啟帳號登錄,如果你是希望不需要帳號就可以直接分享,那你要設定成這 security = share。

    接著我們要設定分享目錄,假如我們已經在/底下建立一個權限為755的share資料夾。

    那在smb.conf最底下要這樣設定:

    [share]

    path=/share

    read only= no

    create mask = 0644

    directory mask 0755

    設定檔案遮罩目的是希望Windows不要去刪除由linux端所建立的資料,設定好後存檔重新啟動smaba:

    sudo /etc/init.d/samba start

    最後在設定一下samba登錄所需的帳號密碼

    sudo smbpasswd -a account

    其中account是必須由linux本機底下已存在的帳號。

    一切就緒,我們再重新啟動一下samba即可:

    sudo /etc/init.d/samba restart

UTips. 44: SSH Connection

  • SSH Connection
  • 在linux底下要做比較安全的遠端連線我們會使用SSH,Server端要安裝的檔案如下:

    • sudo apt-get install openssh-server

    Client端使用以下的方式來連線:

    • ssh account@server's IP

    • ssh -l account server's IP

    這裡的account是Server上的帳號。

  • scp
  • 除了遠端連線之外,我們還需要使用到檔案傳輸,這裡我們可以使用ssh內提供的工具來達成。

    • scp "filename" account@server's IP:"target directory"

    透過上面的方式我們就簡單的將client端的檔案上傳到server端上。

  • sftp
  • 同時我們也會需要用到ftp的功能,這裡我們也可以直接使用sftp這個指令

    • sftp account@server's IP

    連上去之後操作方式跟一般ftp的使用方式一樣。

UTips. 43: Unable to resolve host name

  • Unable to resolve host name
  • 最近在變更host name之後忽然出現了這個訊息,解決方式如下:

    • sudo nano /etc/hosts

    你會看到127.XXX等ip組,將他們設定成如下的形式

    127.0.0.1 你的電腦名稱.網域名稱 localhost
    127.0.1.1 你的電腦名稱.網域名稱 localhost

    以我的例子來說,我的host name是user-desktop,我的區域網路ip是192.168.2.2。那我的設定會如下:

    127.0.0.1 user-desktop.user-desktop localhost
    127.0.1.1 user-desktop.user-desktop localhost

    192.168.2.2 user-desktop.user-desktop user-desktop

    存檔離開即生效。

UTips. 42: Boot in Text/Command/Console Mode

  • Boot in Text/Command/Console Mode
  • 以往這些設定我們會在/etc/inittab裡修改,但是我發現ubuntu並沒有這個檔案,所以只好使用下面的方式。

    停用系統自動登入gdm圖形化桌面

    • sudo update-rc.d -f gdm remove

    啟用系統自動登入gdm圖形化桌面

    • sudo update-rc.d -f gdm defaults

UTips. 41: VMware in Ubuntu

  • VMware in Ubuntu
  • 其實如果沒有特殊需求,我還真的不建議你在ubuntu底下裝VMware,一方面是安裝比較沒有VirtualBox方便,再者就是效能上也沒有VirtualBox好。

    官方首頁:http://www.vmware.com/

    下載之前請先到這裡註冊一個免費的序號

    http://register.vmware.com/content/registration.html

    下載頁面:

    http://register.vmware.com/content/download-106.html

    安裝VMware之前請先安裝xinetd

    sudo apt-get install xinetd

    以下所需的檔案都可在官方下載頁面找到,除了any-any-update116之外,

    接著安裝VMware-server-1.0.6-91891.tar.gz

    • tar xzf VMware-server-1.0.6-91891.tar.gz -C /tmp
    • cd /tmp/vmware-server-distrib
    • sudo ./vmware-install.pl
    再來安裝更新包 vmware-any-any-update116.tar

    • tar xzf vmware-any-any-update116.tar.gz -C /tmp
    • cd /tmp/vmware-any-any-update116
    • sudo ./runme.pl

    最後安裝VMware Server Console

    • unzip VMware-server-linux-client-1.0.6-91891.zip
    • tar xzf VMware-server-console-1.0.6-91891.tar.gz -C /tmp
    • cd /tmp/vmware-server-console-distrib
    • sudo ./vmware-install.pl

    安裝完成後你會發現你的VMware Server Console執行不起來,這時建議你將下列兩個檔案刪除:

    • rm -rf /usr/lib/vmware/lib/libgcc_s.so.1/libgcc_s.so.1
    • rm -rf /usr/lib/vmware/lib/libpng12.so.0/libpng12.so

    接著執行sudo vmware應該就ok了。

[C/C++] Calling Gnuplot in C

  • Calling Gnuplot in C
  • Download:callGnuPlot.c

    懶惰是程式設計師的天性,所以才會創造出許多方便的程式,最近一直需要作圖分析,厭倦了Origin重複且繁複的設定,所以決定將要分析的資料使用c做分析後再由gnuplot畫出。

    熟悉gnuplot的人都知道我們可以將常用的指令寫在一個檔案上,然後只需需要讀取那個檔案就可以畫出我們設定好的樣子(如同matlab的m file)。透過這樣的特性我們可以直接使用system("gnuplot 'script'");的形式來呼叫gnuplot畫圖。這裡我介紹一個比較傳統方式的呼叫,使用mkstemp(), popen()等函式來完成。

    使用mkstemp來幫我們自動產生暫存用的檔案,這裡我們分別要畫sin(x),cos(x),但是我們只需要宣告一個檔案即可,因為gnuplot有一些方便的指令在讀取資料時以各個column為基準。

    將我們要作圖的資料寫在剛剛宣告的暫存檔案中。

    設定我們要繪圖的指令。

    最後記得將畫面給暫停住,否則你的圖形只會出現一瞬間。

    輸出的圖形圖下:

    PS. 以上只是個範例,如果你的圖形是可以用方程式給精準地表示出來的,那就不用上面的麻煩方式,你大可直接使用octave,scilab還比較快。

[C/C++] Structure Size

  • Structure Size

    這是一個程式設計師在處理structure常會忽略的問題,舉以下的範例來說明:

    預期之下我們會認為是30+4 bytes,但是實際輸出是36 bytes,當然這是可以解釋的,因為編譯器要為CPU做最佳化處理,所以檔案大小會對齊於可除4的位置,所以結果才會是36bytes。

    這樣的特性卻很有可能造成另一個問題,尤其是當我們在處理影音的程式時,我們並需要大量的讀寫結構體,當結構體變得很複雜時,你很難掌控結構體大小,錯誤很有可能就在這個時候發生,所以在處理多型態混雜的結構體時,我會用下面的方式宣告。

    使用#pragma強制結構體的宣告依照我們所定義的大小而定,雖然這樣做事必會損失一點執行效率,但是在處理複雜的程式時,像是大型的genetic programming,我們寧可選擇讓結構體不最佳化來宣告,以避免出錯時要花更多的時間去debug,甚至你有可能完全忽略他所造成的錯誤,進而產生錯誤的數據。

Orange - data analysis tool

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