1. 程式人生 > >結對程式設計專案——C語言實現WordCount Web化

結對程式設計專案——C語言實現WordCount Web化

結對程式設計專案

程式碼地址

201631062219,201631011410

gitee專案地址:https://gitee.com/xxlznb/pair_programming

作業地址:https://edu.cnblogs.com/campus/xnsy/2018Systemanalysisanddesign/homework/2188

團隊PSP

PSP2.1 PSP階段 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 30 40
-Estimate -估計這個任務需要多少時間 20 25
Development 開發 600 740
-Analysis -需求分析 120 80
-Design Spec -生產設計文件 0 0
-Design Review -設計複審 0 0
-Coding Standard -程式碼規範 10 10
-Design 具體設計 100 240
-Coding -具體編碼 360 480
-Code Review -程式碼複審 30 60
-Test -測試 90 30
Reporting 報告 60 60
-Test Report -測試報告 0 0
- Size Measurement -計算工作量 0 0
-Postmortem & Process Improvement Plan 事後總結,提出過程改進計劃 30 30
合計 810 985

專案介紹

專案的主要語言為C語言,C語言作為一種平臺依賴性較小的語言,同時也是效能非常優秀的語言,同時也是為了玩,所以我們使用了C語言作為開發語言,但是C語言的圖形介面並不方便使用,因此我們換了一個思路,我們將這個專案web化了。

同時,web後端也使用C作為開發語言。伺服器架構為Apache+CGIC庫

CGI——common gateway interface,通用閘道器介面,我們將客戶端提交的http請求通過Apache伺服器拆解後傳送至CGI程式,由CGI程式處理後輸出相應,在此專案中,我們需要解決多檔案上傳的問題,我們使用CGIC庫協助我們開發,CGIC庫是一個極度簡單的庫(https://boutell.com/cgic/)這裡為他的主頁

2018-10-17 21:48:13螢幕截圖

以上為處理邏輯,我們為了保證原始執行程式的獨立性,我們只對起做基礎包裝,CGIC庫由於不信任臨時檔案,因此在API中隱藏了臨時檔案的資訊,無法直接獲取臨時檔案,它推薦的做法是,如果需要儲存檔案則直接提供臨時檔案指標,但我們的wc是輸入檔案路徑的,為了直接獲取CGIC的臨時檔案路徑,我們得修改庫函式,在cgi.c中新增

cgiFormResultType cgiFormTempFileName(
    char *name, char *result, int resultSpace)
{
    cgiFormEntry *e;
    int resultLen = 0;
    char *s;
    e = cgiFormEntryFindFirst(name);
    if(!e){
        strcpy(result,"");
        return cgiFormNotFound;
    }
    s = e->tfileName;
    while(*s) {
        APPEND(result, *s);
        s++;
    }
    if(resultSpace) {
        result[resultLen] = '\0';
    }
    if(!strlen(e->tfileName)) {
        return cgiFormNoFileName;
    } else if (((int) strlen(e->tfileName)) > (resultSpace - 1)) {
        return cgiFormTruncated;
    } else {
        return cgiFormSuccess;
    }

}

同時在cgi.h中新增

extern cgiFormResultType cgiFormTempFileName(
    char *name, char *result, int max);

之後就可以通過這個函式直接獲取臨時檔案的路徑了,之後我們將臨時檔案與檔案對應的checkbox中的資料進行拼接即可獲得一條shell命令。

在獲取到命令後,我們使用popen

popen()函式通過建立一個管道,呼叫fork()產生一個子程序,執行一個shell以執行命令來開啟一個程序。可以通過這個管道執行標準輸入輸出操作。這個管道必須由pclose()函式關閉,必須由pclose()函式關閉,必須由pclose()函式關閉,而不是fclose()函式(若使用fclose則會產生殭屍程序)。pclose()函式關閉標準I/O流,等待命令執行結束,然後返回shell的終止狀態。如果shell不能被執行,則pclose()返回的終止狀態與shell已執行exit一樣。

type引數只能是讀或者寫中的一種,得到的返回值(標準I/O流)也具有和type相應的只讀或只寫型別。如果type是"r"則檔案指標連線到command的標準輸出;如果type是"w"則檔案指標連線到command的標準輸入。command引數是一個指向以NULL結束的shell命令字串的指標。這行命令將被傳到bin/sh並使用-c標誌,shell將執行這個命令。

popen()的返回值是個標準I/O流,必須由pclose來終止。前面提到這個流是單向的(只能用於讀或寫)。向這個流寫內容相當於寫入該命令的標準輸入,命令的標準輸出和呼叫popen()的程序相同;與之相反的,從流中讀資料相當於讀取命令的標準輸出,命令的標準輸入和呼叫popen()的程序相同。

FILE *fp = NULL; 
char c;
fp = popen(command, "r");
if(!fp)
{
    perror("popen");
    exit(EXIT_FAILURE);
} 
while(!feof(fp))
{
    c=fgetc(fp);
    if(c==-1)break;
    printf("%c",c);
}
pclose(fp);

目前已知的問題

前端醜,後端處理後的返回頁面沒有做,部分功能沒有實現。仍待優化。

專案總結

總結:

通過本次專案,我們學到了很多一個人做專案的時候不會學到的東西,掌握了很多新知識,學了很多之前想學而又沒時間學習的知識。

首先從結對的角度上來說,一個人寫程式碼的過程是枯燥的,而兩個人可以很好的從隊友的反饋中調節自己的心態,能夠在最艱難的時期咬牙堅持下去。在做停用詞功能的時候,由於在一個過程函式中返回了棧中的指標,導致外部程式永遠都無法正確地訪問到真正的字串地址,最恐怖的是他在除錯的時候一切都是正常的,直到這部分記憶體被回收之後程式才會報錯。我在這個部分卡了整整半個小時,直到後來意識到靠自己確實無法解決這個BUG之後,叫來了結對的小夥伴,我們倆一起審查程式碼過後找到了原因。這是我在這個專案過程中離放棄最近的一次,多虧結對程式設計,我最後才能成功解決這個BUG。並且兩個人一起寫程式碼過程中,積極性都普遍高於一個人寫程式碼,做專案的這幾天裡,除了其他不得不完成的任務,其他的時間幾乎全部投入到了程式碼的編寫及測試的過程中。

其次從專案內容的角度上來說,我們專案的獨立性非常高,從前端到處理Http請求,從Http請求到引數的獲取以及檔案的獲取,從引數到檔案的獲取到引數的解析以及檔案的處理,整個過程基本上都是由我們自己從底層自己搭建的。也因此我們花費了大量的時間去造輪子,導致花在專案主體上的時間不夠多,因此可能一部分功能還待實現。但是我們的目標是把這個專案做大做好,不僅僅是為了應付這一次作業,而是做一個長期的打算,通過這個專案去學習我們之前沒有學習過的內容,掌握我們還不熟悉的知識,不斷將我們的專案完善。

從程式碼上來看,我們程式碼耦合度不高,符合面向過程設計規範,很多程式碼都可以複用。並且我們從開始就考慮了可拓展性,很多可能幾行程式碼就可以實現的功能我們都儘量做到泛化,增強它的可拓展性。正如前面所提到的,我們將這個專案作為一個長期專案來考慮,避免Magic Number以及模稜兩可的變數名,做到看名其意。

從優化的角度上來看,我們計劃在接下來的時間實現多程序取檔案,提升讀取效率。權衡時間與空間複雜度,將涉及到查詢的程式碼重構成具有更高效率的查詢方式。將前端的頁面重新設計並實現。

總而言之,本次專案收穫很多,"Learning by doing",孔子曾經說過:“吾聽吾忘,吾見吾記,吾做吾悟”,我們在以後的學習中,任將承這種學習態度,在實踐中感悟,在實踐中成長。