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