結對程式設計專案——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/)這裡為他的主頁。
以上為處理邏輯,我們為了保證原始執行程式的獨立性,我們只對起做基礎包裝,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",孔子曾經說過:“吾聽吾忘,吾見吾記,吾做吾悟”,我們在以後的學習中,任將承這種學習態度,在實踐中感悟,在實踐中成長。