大型作業(yè)答辯:C/S考試系統(tǒng)程序制作詳解
作者:姚明
下載源代碼
程序組成結(jié)構(gòu)
一、服務(wù)器程序
- 采用了WinSocket32的完成端口模型(I/O completion ports)
- WIN32多線程技術(shù)
- ODBC APIS 進(jìn)行數(shù)據(jù)庫(kù)操作
二、客戶(hù)端程序
用Win32 API函數(shù)構(gòu)造主窗體和界面元素,如圖一所示:
 圖一 程序組織結(jié)構(gòu)
服務(wù)器程序詳解
一、完全端口模型(I/O completion ports)是迄今為止最為復(fù)雜的一種I/O模型,假如一個(gè)程序需要管理為數(shù)眾多的套接字,那么采用這種模型往往可以達(dá)到最佳的系統(tǒng)性能,不幸的是該模型只適用與WIN2000和WINNT操作系統(tǒng),因其設(shè)計(jì)的復(fù)雜性,只有在你的應(yīng)用程序需要同時(shí)管理數(shù)百乃至上千個(gè)套接字的時(shí)候,而且希望隨著系統(tǒng)內(nèi)安裝的CPU的數(shù)量增多,應(yīng)用程序的性能也可以線性的提升,才考慮采用“完成端口模型”(WEB服務(wù)器便是這方面的典型例子)。I/O completion ports是唯一適用于高負(fù)載服務(wù)器的一個(gè)技術(shù),它利用一些線程幫助平衡“I/O請(qǐng)求”所引起的負(fù)載,這樣的構(gòu)架特別適合應(yīng)用在SMP系統(tǒng)中產(chǎn)生所謂的“Scalable”服務(wù)器,(Scalable是指能夠籍著增加RAM或磁盤(pán)空間,CPU個(gè)數(shù)而提升應(yīng)用程序效能的一種系統(tǒng))。
二、完全端口模型的具體實(shí)現(xiàn) 為了使用“完成端口模型”,我產(chǎn)生了一堆線程在端口上等待,線程數(shù)量=CPU個(gè)數(shù)x2+2,我將每個(gè)客戶(hù)端產(chǎn)生的文件句柄與I/O completion ports端口相關(guān)聯(lián),建立了這種關(guān)系之后,任何客戶(hù)端發(fā)出操作請(qǐng)求,便會(huì)導(dǎo)致I/O completion packet被送到“完成端口”去,這個(gè)步驟是操作系統(tǒng)完成的,為了回應(yīng)I/O completion packet,我讓I/O completion釋放一個(gè)等待中的線程,如果目前沒(méi)有線程正在等待,它不會(huì)為這個(gè)客戶(hù)端N產(chǎn)生新的線程, 當(dāng)作用中的線程處理完相應(yīng)客戶(hù)端的“overlapped I/O”后,將返回I/O completion端口進(jìn)行等待,客戶(hù)端N這時(shí)才能夠被處理,這樣就保證了我的Workers線程總是保持一個(gè)穩(wěn)定的數(shù)量(CPU個(gè)數(shù)x2+2)。如圖二所示:
 圖二 完全端口線程模型示意圖
三、數(shù)據(jù)庫(kù)的操作實(shí)現(xiàn) 這部分功能主要是通過(guò)WinSocket32 API和ODBC API結(jié)合使用來(lái)實(shí)現(xiàn)的,服務(wù)端進(jìn)入監(jiān)聽(tīng)狀態(tài)后,為每個(gè)客戶(hù)端提供相應(yīng)線程處理發(fā)過(guò)來(lái)的指令,通過(guò)分析指令,作出以下相應(yīng)的操作: 客戶(hù)端發(fā)送的指令(自定義的):
login: 登陸校驗(yàn) 參數(shù):用戶(hù)名,科目,密碼
Srecv:ScanTm: 檢查服務(wù)器時(shí)間校對(duì)試卷修改試卷狀態(tài),拋出計(jì)數(shù)值
Srecv:GetSta: 獲取試卷狀態(tài)
Srecv:GetRlt: 獲取上次做答
Srecv:GetNum: 獲得試卷相關(guān)信息(總題數(shù),開(kāi)考時(shí)間,結(jié)束時(shí)間)
Srecv:GetQue: 獲取試卷題目?jī)?nèi)容.
Srecv:SaveDt: 保存試卷
Srecv:ChanST: 修改試卷狀態(tài).
四、服務(wù)器程序總結(jié) 數(shù)據(jù)庫(kù)被單獨(dú)存放在一個(gè)服務(wù)器中可以保證數(shù)據(jù)安全性,程序會(huì)將客戶(hù)端的一切操作顯示在窗口中,用戶(hù)可以通過(guò)觀察窗口,知道所有客戶(hù)端的動(dòng)作。這個(gè)程序采用“完成端口”模型,可以滿(mǎn)足大規(guī)模的考試需求。
客戶(hù)端程序詳解 一、窗口完全采用Win32API函數(shù)生成 主要包含一下標(biāo)準(zhǔn)控件:
static控件
Edit控件
Button控件
Scroll控件
窗口元素全部采用計(jì)算后的相對(duì)坐標(biāo)定位,所以800X600和1024X768下均能正常顯示,
二、試卷的初始化 考慮到每張?jiān)嚲淼念}目數(shù)量都不同,為了節(jié)約內(nèi)存空間,所以我在堆中動(dòng)態(tài)生成了一個(gè)試卷結(jié)構(gòu)體,通過(guò)向服務(wù)器程序發(fā)送GetNum:指令來(lái)獲得試卷總題數(shù)QuestionNum,然后使用TestPaper=new TestRubric [QuestionNum]
/*結(jié)構(gòu)體定義*/
//試卷每道題的結(jié)構(gòu)
struct Questions{
BOOL state;
char Text [512];
};
struct SelectObject{
BOOL state;
char Text[256];
};
struct TestRubric{
struct Questions Tile;
struct SelectObject choose [4];
};
由于TextOut函數(shù)不支持自動(dòng)換行,所以換行操作必須由我自己完成.因此我用同樣的方法在堆中創(chuàng)建了一個(gè)Screen用作屏幕顯示的結(jié)構(gòu)體
Screen=new Lines[LINES]
struct Lines{
int earmark; //用來(lái)存儲(chǔ)Button的ID
BOOL color1;//置顏色標(biāo)志
BOOL color2;//置顏色標(biāo)志
char Line [512];
};
LINES=掃描TestPaper中超過(guò)屏幕寬度的行數(shù)+ QuestionNum*5+QuestionNum*3 屏幕寬度=客戶(hù)區(qū)的寬/每個(gè)文字的寬度/2*2 屏幕高度=客戶(hù)區(qū)的高/每個(gè)文字的高度 為每一體產(chǎn)生4個(gè)互斥的按鈕 按鈕總數(shù)= QuestionNum*4 在堆中生成hWndList數(shù)組保存按鈕handle hWndList=new hWnd [QuestionNum*4] 按鈕ID=題號(hào)*10+選項(xiàng)號(hào) Screen.earmark=按鈕ID
 圖三
將TestPaper中的內(nèi)容經(jīng)過(guò)換行處理之后Copy到Screen結(jié)構(gòu)中,并設(shè)置好Screen.earmark,Screen.Color1, Screen.Color2。在主窗口消息循環(huán)的WM_PAINT消息中將Screen.Line顯示在窗口中:
TextOut(hdc,x,cyhar*i,Screen.Line,strlen(Screen.Line));
并檢查Screen.earmark中是否為零,不為零就:
ShowWindow(hWndList[Sreen.earmark/10-1] [Screen.earmark%10-1],1);
Screen.Color1, Screen.Color2是否為1,如果為1,則改變顏色顯示。
三、換行中存在的問(wèn)題 行寬=客戶(hù)區(qū)的象素寬/每個(gè)文字的寬度/2*2是偶數(shù); 漢字占用雙字節(jié),字母和標(biāo)點(diǎn)符號(hào)占用單字節(jié); 一行文字=字母+標(biāo)點(diǎn)+漢字 (有可能產(chǎn)生奇數(shù)寬); 當(dāng)一行文字產(chǎn)生一個(gè)奇數(shù)寬,最后一個(gè)字符又是漢字的時(shí),就會(huì)把這個(gè)漢字切成兩份,另一半會(huì)在下一行中顯示,這就造成了亂碼; 我的解決辦法是在換行時(shí)增加一個(gè)變量HanChar=0,當(dāng)掃描到字母或是標(biāo)點(diǎn)時(shí),就HanChar++。一行文字掃描完后需要另起一行時(shí),判斷HanChar的奇偶性,當(dāng)為奇數(shù)時(shí)行寬往里縮進(jìn)一個(gè)字節(jié),以避免以上情況。
四、客戶(hù)端程序總結(jié) 由于客戶(hù)端界面采用大量計(jì)算,顯示的內(nèi)容不會(huì)是固定的模式,他會(huì)根據(jù)題目的長(zhǎng)短變化作出相應(yīng)調(diào)整,以達(dá)到最好的顯示效果。 當(dāng)用戶(hù)登陸驗(yàn)證成功之后,服務(wù)器會(huì)拋一個(gè)時(shí)間計(jì)數(shù),客戶(hù)端通過(guò)一個(gè)定時(shí)器,每隔1秒鐘將計(jì)數(shù)減1,并顯示倒計(jì)時(shí)在界面上,直到計(jì)數(shù)為0,表明考試結(jié)束,程序自動(dòng)保存數(shù)據(jù)退出。這樣做的好處是用戶(hù)更改客戶(hù)端的時(shí)間,不會(huì)影響程序的正常計(jì)時(shí)。 客戶(hù)端每隔10秒鐘自動(dòng)保存一次數(shù)據(jù),以防突然死機(jī)之類(lèi)的情況,死機(jī)后再次登陸,程序會(huì)自動(dòng)加載你先前保存的作答。但點(diǎn)擊“提交試卷”后就無(wú)法登陸了。
對(duì)例子程序的說(shuō)明 隨付的程序和源碼是我大型作業(yè)的作品,運(yùn)行時(shí)先運(yùn)行服務(wù)器程序,再運(yùn)行服務(wù)端程序.

帳號(hào):姚明 密碼:1981922
運(yùn)行之前請(qǐng)先調(diào)整數(shù)據(jù)庫(kù)的試卷信息表的開(kāi)考時(shí)間和結(jié)束時(shí)間。還要確保學(xué)生試卷成績(jī)表里面“姚明”那一行中試卷狀態(tài)為1。
作者信息 姚明/Ym 郵箱:yaomingmail@sina.com QQ:31547735 另外我不會(huì)打籃球 :-)
[代碼性質(zhì)] VC完整應(yīng)用程序代碼 [代碼作者] 姚明/Ym [文件大小] 162K [更新日期] 2004-1-17 19:43:00 [下載次數(shù)] 13112 
(END)
|