呂英華
(北海職業(yè)學(xué)院,廣西 北海 536000)
Online Judge系統(tǒng)是一個(gè)在線判題系統(tǒng),能夠?qū)τ脩籼峤坏亩喾N程序源代碼進(jìn)行編譯執(zhí)行,并根據(jù)預(yù)先存儲(chǔ)的結(jié)果進(jìn)行校驗(yàn)后得到源程序的正確性。Online Judge系統(tǒng)最初使用于ACM比賽中[1],隨著國內(nèi)計(jì)算機(jī)行業(yè)的不斷發(fā)展,許多高校開發(fā)了屬于自己的Online Judge系統(tǒng),同時(shí)計(jì)算機(jī)行業(yè)也開發(fā)了Online Judge系統(tǒng)服務(wù)于個(gè)人或他人?,F(xiàn)在Online Judge系統(tǒng)不僅在比賽中使用,還在教學(xué)、考試、程序上機(jī)實(shí)踐中使用,極大提高了教學(xué)工作效率和方便了各類編程人員。
Online Judge系統(tǒng)主要有兩種典型的模式,分別是C/S模式和B/S模式。C/S模式主要用在各種大型比賽中,比如省賽、區(qū)賽、國際賽等;B/S模式主要用在教學(xué)、上機(jī)練習(xí)等。該Online Judge系統(tǒng)采用B/S模式,主要由前端、后端及判題機(jī)三大部分組成。整個(gè)系統(tǒng)以數(shù)據(jù)庫為中心,用戶在前端頁面登錄進(jìn)入系統(tǒng),前端頁面則顯示從數(shù)據(jù)庫中獲取的題目、比賽列表、排名等信息,用戶選擇對(duì)應(yīng)的題目進(jìn)行答題,提交代碼保存至數(shù)據(jù)庫。判題機(jī)是Online Judge系統(tǒng)的核心部分,評(píng)判之前先從數(shù)據(jù)庫中提取代碼,將代碼保存至文件中,再對(duì)代碼文件進(jìn)行編譯、執(zhí)行和評(píng)判操作,最后將評(píng)判結(jié)果存入數(shù)據(jù)庫中,以上則完成了評(píng)判流程,前端頁面則將評(píng)判結(jié)果從數(shù)據(jù)庫中讀取出來并顯示。系統(tǒng)邏輯圖如圖1所示。
圖1 系統(tǒng)邏輯
判題機(jī)是整個(gè)Online Judge系統(tǒng)的核心內(nèi)容,主要功能是對(duì)用戶提交的代碼進(jìn)行編譯、執(zhí)行、評(píng)判等,寫好的判題機(jī)可以放入Windows環(huán)境或Linux環(huán)境中。該Online Judge系統(tǒng)采用Python實(shí)現(xiàn),支持多種程序(如C、C++、java)源代碼編譯執(zhí)行。
Online Judge系統(tǒng)最重要的功能是支持多種編程語言提交代碼,由于不同的編程語言需要到不同的編譯器,則可以選擇Python提供的subprocess模塊去調(diào)用外部編譯器,該模塊能夠?qū)Σ煌幊陶Z言進(jìn)行擴(kuò)展,只需配置好編譯參數(shù)即可。
具體實(shí)現(xiàn)是調(diào)用subprocess.Popen方法,設(shè)置方法中的shell=True,并使用cwd指定工作目錄,stdout和stderr設(shè)置為subprocess.PIPE管道。調(diào)用communicate方法獲取外部程序的輸出信息,一般返回0和1。
p=subprocess.Popen(build_cmd[language],shell=True,cwd=dir_work,stdout=subprocess.PIPE,stderr=subprocess.PIPE) #調(diào)用subprocess.Popen
out,err=p.communicate() #獲取編譯錯(cuò)誤信息
判題機(jī)的評(píng)判流程是根據(jù)代碼編譯執(zhí)行后返回的信息做出對(duì)應(yīng)的執(zhí)行流程。首先,communicate方法如果出現(xiàn)編譯錯(cuò)誤Compile Error,則停止,否則繼續(xù)往下執(zhí)行;其次,判題機(jī)會(huì)依次檢查程序是否出現(xiàn)超時(shí)、超內(nèi)存和非法指針、數(shù)組越界等情況,如果程序返回Time Limit Exceeded錯(cuò)誤信息,則說明執(zhí)行超時(shí)了;如果程序返回Memory Limit Exceeded錯(cuò)誤信息,則說明執(zhí)行超出內(nèi)存限制了;如果程序返回Runtime Error錯(cuò)誤信息,則說明程序運(yùn)行錯(cuò)誤,需要進(jìn)行修改[2]。評(píng)判流程圖如圖2所示。
圖2 評(píng)判流程
當(dāng)以上所有流程跑完,都未出現(xiàn)錯(cuò)誤信息,程序繼續(xù)執(zhí)行,下一步驟,則需要將結(jié)果和標(biāo)準(zhǔn)答案進(jìn)行比較,得出答題是否正確,有以下幾種比較情況。
(1)當(dāng)程序運(yùn)行結(jié)果和預(yù)設(shè)的標(biāo)準(zhǔn)答案一致,則程序會(huì)返回Accepted,說明答題成功;
(2)將程序運(yùn)行結(jié)果中無用的空格符、換行符等去掉后與預(yù)設(shè)的標(biāo)準(zhǔn)答案是一致的,則程序會(huì)返回Presentation Error,說明運(yùn)行結(jié)果格式有誤;
(3)當(dāng)程序運(yùn)行結(jié)果和預(yù)設(shè)的標(biāo)準(zhǔn)答案不一致,則返回Wrong Answer,說明答題失?。?];
(4)如果程序運(yùn)行結(jié)果僅有一部分和預(yù)設(shè)的標(biāo)準(zhǔn)答案一致,會(huì)返回Output Limit Exceeded。
檢測(cè)程序的執(zhí)行時(shí)間和內(nèi)存,可以通過github上的一個(gè)開源項(xiàng)目lorun去實(shí)現(xiàn)。該開源項(xiàng)目是利用C語言編寫的一個(gè)Python擴(kuò)展模塊,使程序能夠在一個(gè)類似沙盒的環(huán)境下執(zhí)行,并能夠精準(zhǔn)地獲取程序的執(zhí)行時(shí)間和內(nèi)存,還能對(duì)程序進(jìn)行限制,防止外部調(diào)用。
Online Judge系統(tǒng)還要做好安全處理,防止用戶惡意攻擊破壞系統(tǒng)。解決該問題,可以從以下方面進(jìn)行處理。
(1)通過防火墻限制網(wǎng)絡(luò)訪問,或者禁止系統(tǒng)連接外網(wǎng);
(2)對(duì)代碼進(jìn)行預(yù)先檢查;
(3)將判題機(jī)和服務(wù)器進(jìn)行分離;
(4)控制文件的執(zhí)行權(quán)限;
(5)設(shè)置沙盒環(huán)境,將程序執(zhí)行環(huán)境和外部進(jìn)行隔離。可以從操作系統(tǒng)中設(shè)置,如設(shè)置Linux環(huán)境chroot命令,也可以使用Python的方法實(shí)現(xiàn)。
設(shè)計(jì)一款完善的判題機(jī)需要用到的技術(shù)除了整套的web技術(shù)棧外,還需要操作系統(tǒng)、沙箱等知識(shí),屬實(shí)不容易。該判題機(jī)的設(shè)計(jì)借助了網(wǎng)上多位大神的邏輯、經(jīng)驗(yàn)、代碼,目前已能夠正常使用,但還需進(jìn)行優(yōu)化改進(jìn)。