機(jī)考系統(tǒng)中的交/發(fā)卷設(shè)計(jì)
發(fā)表時(shí)間:2023-08-16 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]作者: 楊家成 大多數(shù)計(jì)算機(jī)考試需要進(jìn)行機(jī)試(如計(jì)算機(jī)等級(jí)考試),在機(jī)試中會(huì)碰到如何給考生分發(fā)試卷及回收答卷等問(wèn)題。一般的解決方案是: 采用軟盤;在服務(wù)器上建立考生文件夾,設(shè)置登錄密碼或進(jìn)行登錄...
作者: 楊家成
大多數(shù)計(jì)算機(jī)考試需要進(jìn)行機(jī)試(如計(jì)算機(jī)等級(jí)考試),在機(jī)試中會(huì)碰到如何給考生分發(fā)試卷及回收答卷等問(wèn)題。一般的解決方案是: 采用軟盤;在服務(wù)器上建立考生文件夾,設(shè)置登錄密碼或進(jìn)行登錄限制;基于文件夾共享,以文件復(fù)制方式實(shí)現(xiàn)發(fā)卷、交卷。這些方案在實(shí)施過(guò)程中都存在不少問(wèn)題,如軟盤的意外損壞; 工作量太大,操作太煩瑣; 共享出來(lái)的交卷文件夾可能被考生識(shí)破而導(dǎo)致安全隱患等等。相比而言, 采用基于Winsock的文件傳輸方式進(jìn)行發(fā)卷、交卷可以在一定程度上解決這個(gè)問(wèn)題。實(shí)踐證明,這是一個(gè)行之有效的方案,本文針對(duì)這一方案進(jìn)行介紹。
編程思路
本系統(tǒng)的基本思路是: 在局域網(wǎng)環(huán)境下,考試前把各卷別的考試文件分別壓縮,放在服務(wù)器的某個(gè)文件夾中,服務(wù)器端執(zhí)行服務(wù)器程序,負(fù)責(zé)接收考生的請(qǐng)求并做出響應(yīng)。各考生執(zhí)行客戶端程序,先通過(guò)其中的發(fā)卷模塊向服務(wù)器請(qǐng)求把考試文件發(fā)送到考生的本地硬盤,考試完成后再通過(guò)其中的交卷模塊把答案發(fā)送回服務(wù)器。由于文件的發(fā)送是基于TCP協(xié)議的端口通信,考生無(wú)從知道試題及答案放在哪里,很好地解決了安全問(wèn)題。下面是本系統(tǒng)實(shí)現(xiàn)過(guò)程中的一些關(guān)鍵問(wèn)題:
1. 多連接的實(shí)現(xiàn)
由于有多個(gè)考生參加考試,每個(gè)考生都要與服務(wù)器建立一個(gè)連接,為此在服務(wù)器程序中采用動(dòng)態(tài)建立多連接,即采用Winsock控件數(shù)組。
2.?dāng)?shù)據(jù)類型
發(fā)送的數(shù)據(jù)類型通常有字串流(String)和字節(jié)流(Char數(shù)組)兩種。前者一般用于發(fā)送輔助信息,如文件大小、考生信息等,后者用于發(fā)送文件正文。
3. 發(fā)送、接收結(jié)束的判斷
每進(jìn)行一次發(fā)送(或接收)后,將已發(fā)送(或已接收)的字節(jié)數(shù)與源文件的大小進(jìn)行比較,判定是否結(jié)束。
4.文件夾的發(fā)送
Winsock控件只能發(fā)送文件,但考試中常常包含文件夾。怎么辦?辦法是先在程序中調(diào)用壓縮軟件將其壓縮成單個(gè)文件再發(fā)送,接收方在接收完后進(jìn)行解壓縮還原。這是本系統(tǒng)的一個(gè)關(guān)鍵思路。
5.等待壓縮/解壓縮的完成
由于壓縮/解壓縮程序是通過(guò)VB的Shell函數(shù)調(diào)用執(zhí)行的,而Shell是以異步方式執(zhí)行壓縮/解壓縮程序的,這樣就會(huì)出現(xiàn)沒(méi)等壓縮/解壓縮完成,VB代碼繼續(xù)往下執(zhí)行的情況。為此需要借助OpenProcess、GetExitCodeProcess這兩個(gè)Windows API,通過(guò)循環(huán)讀取進(jìn)程狀態(tài)值控制程序的等待。
6.注意事項(xiàng)
發(fā)送方在發(fā)送數(shù)據(jù)時(shí)采用間歇方式,否則易造成客戶端數(shù)據(jù)丟失,通常的做法是執(zhí)行VB的DoEvents語(yǔ)句。接收方在接收期間不能出現(xiàn)與用戶進(jìn)行交互的等待狀態(tài),否則會(huì)耽誤接收,造成數(shù)據(jù)丟失。
服務(wù)器端接收考生交卷時(shí),應(yīng)接收完所有考生的壓縮文件后,再統(tǒng)一進(jìn)行解壓縮,否則會(huì)加重服務(wù)器的負(fù)擔(dān)。
7. 程序流程
客戶端程序、服務(wù)器程序的流程圖分別如圖1、圖2所示:
關(guān)鍵代碼
1.建立保存考生信息的數(shù)據(jù)類型
先在服務(wù)器程序的標(biāo)準(zhǔn)模塊中創(chuàng)建一個(gè)用于存放每個(gè)連接有關(guān)信息(每個(gè)連接對(duì)應(yīng)一個(gè)考生)的自定義數(shù)據(jù)類型ClientConn:
Public Type ClientConn
Recvd As Boolean ’是否已接收過(guò)數(shù)據(jù)
FileNum As Integer ’文件號(hào)
FinishSize As Double ’完成收發(fā)的字節(jié)數(shù)
FileSize As Double ’文件的大小
Gh As String * 6 ’交卷者的考號(hào)
Jb As String * 1 ’交卷者的卷別
End Type
在服務(wù)器程序窗體模塊中聲明一個(gè)用于記錄所有連接信息的模塊級(jí)動(dòng)態(tài)數(shù)組Conns:
Dim Conns() As ClientConn
2.服務(wù)器端建立連接:
Private Sub wisServer_ConnectionRequest(Index As Integer, ByVal requestID As Long)
If Index = 0 Then
Conncount = Conncount + 1
’連接總數(shù),為模塊級(jí)變量
Load wisServer(Conncount)
’服務(wù)器端WinSock控件數(shù)組
ReDim Preserve Conns(1 To Conncount)
wisServer(Conncount).LocalPort = 0
wisServer(Conncount).Accept requestID
End If
End Sub
3.發(fā)卷時(shí)服務(wù)器發(fā)送文件正文
Private Sub wisServer_SendComplete(Index As Integer)
Dim DataSize As Integer
Dim outFileData() As Byte
If Conns(Index).FinishSize < Conns(Index).FileSize Then ’此前文件已打開(kāi)
DoEvents
If Conns(Index).FileSize - Loc(Conns(Index).FileNum) < MAXSENDSIZE Then
’MAXSENDSIZE是每次發(fā)送的最大字節(jié)數(shù)
DataSize = Conns(Index).FileSize - Loc(Conns(Index).FileNum)
Else
DataSize = MAXSENDSIZE
End If
ReDim outFileData(0 To DataSize - 1)
Get #Conns(Index).FileNum, , outFileData
wisServer(Index).SendData outFileData
Conns(Index).FinishSize = Conns(Index).FinishSize + DataSize
Else
Close (Conns(Index).FileNum)
End If
End Sub
說(shuō)明:客戶端程序的交卷模塊代碼與此類似。
4. 客戶端接收數(shù)據(jù)代碼
Private Sub wisClient_DataArrival(ByVal bytesTotal As Long)
Dim inData As String
’用于接收輔助信息
Dim inFileData() As Byte
’用于接收文件正文
Dim GetRarFile As String, unRarTarget As String ’文件路徑
If Not Recvd Then ’如果是首次接收
wisClient.GetData inData, vbString
’接收文件的大小信息
FileSize = CDbl(Val(inData))
Recvd = True
Else ’開(kāi)始接收文件正文
ReDim inFileData(0 To bytesTotal - 1)
wisClient.GetData inFileData, vbArray + vbByte
Put FileNum, , inFileData
’此前文件已建立并打開(kāi)
RecvdSize = RecvdSize + bytesTotal
If RecvdSize = FileSize Then
’接收完畢
Close (FileNum)
wisClient.Close
’由接收方關(guān)閉連接而非發(fā)送方,否則會(huì)丟失數(shù)據(jù)
GetRarFile = GhDir & “\” & txtGh & “.rar”
’GhDir是考試目錄,txtGh存放考號(hào)
unRarTarget = GhDir & “\”
Pid = Shell(App.path & “\rar x -inul” & GetRarFile & unRarTarget) ’解壓縮
hProcess=OpenProcess(PROCESS_
QUERY_INFORMATION, 0, Pid)
’調(diào)用WinAPI
Do ’等待解壓縮結(jié)束
Call GetExitCodeProcess(hProcess, ExitCode)
DoEvents
Loop While ExitCode = STILL_ALIVE
Call CloseHandle(hProcess)
Kill GhDir & “\” & txtGh & “.rar”
MsgBox “發(fā)卷完畢”
Shell “C:\Windows\explorer.exe/n,
/e,” & GhDir, vbMaximizedFocus
Unload Me
End If
End If
End Sub
說(shuō)明:服務(wù)器程序中接收交卷的代碼與此相似。
以上代碼已在Windows 2000 Server、Windows XP、Windows 98平臺(tái)下成功運(yùn)行,并在實(shí)踐中獲得成功的應(yīng)用。由于篇幅所限,在此沒(méi)給出完整代碼。
小 結(jié)
在本系統(tǒng)的編程中有兩點(diǎn)值得注意: 一個(gè)是壓縮-發(fā)送-解壓縮的思路,另一個(gè)是用自定義數(shù)據(jù)類型數(shù)組保存考生(連接)的信息。當(dāng)然,本系統(tǒng)只是解決了服務(wù)器與考生用機(jī)之間的安全問(wèn)題,至于考生與考生之間通過(guò)文件夾共享互通答案,也許只有采取暫時(shí)的物理隔離手段才是最有效的解決辦法。