由成幻OnlineJudge学习如何做自己的Acm-Icpc在线评判系统-5.在线编译与测试系统代码粗解

由于近来很忙,加之此类文章少有人问津.所以少有时间写这一系列的文章的续篇
所以先把核心在线编译的代码发出来,细的部分大家可以查资料,或者留言问我^^
部分类库可以查我以前的文章
using System;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.Threading;
using System.IO;

namespace ChswordOJ {
    
/// <summary>
    
/// DoFile 进行在线编译与测试
    
/// Builder:邹健 2007 4 28
    
/// V1.0 2007 6 12
    
/// </summary>
    public class DoFile {
        StringBuilder _output 
= new StringBuilder();
        StringBuilder _TestOutput 
= new StringBuilder();
        StringBuilder _TestFile_Output 
= new StringBuilder();
        String _Test;
        String _CompilerName;
        StringBuilder _CompilerText 
= new StringBuilder();
        
private Int64 _Memory, _myMemory;
        
private Int32 _Time;//, _myTime;
        private Option.AnswerStatus _TestResult;
        
private String _ExePath;
        
private String _CodePath;
        
private String _TextPath;
        
private String _TestPath;
        
private Int64 _AnswerId;
        
private String _Sign;
        
private Boolean _TestEnd;
        Process _process;
        
/// <summary>
        
/// 构造函数,对DoFile类进行初始化
        
/// </summary>
        public DoFile() {
            _Memory 
= 23768;
            _Time 
= 3;
        }
        
/// <summary>
        
/// 进行编译及测试代码。
        
/// </summary>
        
/// <param name="code">要编译的代码。</param>
        
/// <param name="UserName">编译的用户名。</param>
        
/// <param name="PassWord">用户密码。</param>
        
/// <param name="QNum">代码的问题ID。</param>
        
/// <param name="CompilerName">编译器。</param>
        public void GetResult(String code, String UserName, String PassWord, String QNum, String CompilerName) {
            Option cp 
= new Option();
            DataSet ds 
= cp.GetLimit(QNum);
            User u 
= new User(UserName, CompilerName.Split(',')[0], CompilerName.Split(',')[1]);
            _Memory 
= int.Parse(ds.Tables[0].Rows[0][0].ToString());//从数据库读取当前的程序 要求的Memory
            _Time = int.Parse(ds.Tables[0].Rows[0][1].ToString());//从数据库读取当前的程序 要求的Time limit
            _Test = ds.Tables[0].Rows[0]["test"].ToString();//读取测试文件
            _CompilerName = CompilerName;//编译器名称
            _Sign = u.Sign;
            _CodePath 
= u.CodePath;//源代码文件保存的路径
            _TextPath = u.TextPath;//生成文本文件保存的路径
            _ExePath = u.ExePath;//EXE文件保存的路径
            _myMemory = 0;//对我当前耗费的内存进行初始化
            _TestPath = u.GetTestPath(QNum);//得到当前测试路径
            _AnswerId = cp.AddAnswer(UserName, Int64.Parse(QNum), CompilerName);//将当前数据作为一条回答存入数据库(创建一条数据库记录)
            Code cc = new Code(CompilerName, code);//创建Code实例
            if (cc.Check()) {//调用配置文件中的正则表达式,测试代码中有无危险代码,有,则此回答为危险代码

                SaveTextFile(u.CodePath, code);
//将源代码保存为相应格式文件
                _CompilerText.AppendLine(u.CompilerString);//
                DoCmd(u.CompilerString);//用u生成编译字符串,执行编译操作
                IsTempExists(u.TextPath, u.CompilerString);//是否编译完成
                if (0 == _AnswerId)
                    
return;
                cp.SetAnswerStatus(_AnswerId, Option.AnswerStatus.编译中);
                
//编译完成
                if (IsCompilerSucess(u.TextPath, u.CodePath, u.ExePath, 0)) {//编译产生EXE则编译成功
                    
//编译成功
                    cp.SetAnswerStatus(_AnswerId, Option.AnswerStatus.测试中);
                    ThreadStart thr_start_func 
= new ThreadStart(Test);//异步调用Test进行测试
                    Thread fThread = new Thread(thr_start_func);
                    fThread.Name 
= "Test";
                    fThread.Start();
                    Thread.Sleep(_Time 
* 2000);//初始化最大超时时间(规定时间的2倍)
                    if (Option.AnswerStatus.测试通过 == _TestResult) {
                        
//cp.SetAnswerStatus(_AnswerId, Compiler.AnswerStatus.测试通过);
                    }
                    
else {
                        
if (_TestResult == 0) {
                            
try {
                            
//对进程查看是否结束,未结束则进行操作
                                if (!_process.HasExited) {
                                    
if (!_process.CloseMainWindow())
                                        _process.Kill();
                                    
if (_TestFile_Output.ToString().StartsWith(_TestOutput.ToString()))
                                        _TestResult 
= Option.AnswerStatus.超时;
                                    
else
                                        _TestResult 
= Option.AnswerStatus.测试失败;
                                }
                            }
                            
catch {
                                _TestResult 
= Option.AnswerStatus.测试失败;
                            }

                        }
                        
if (fThread.IsAlive) fThread.Abort();//最终的强制结束进程
                    }
                }
                
else {
                    _TestResult 
= Option.AnswerStatus.编译失败;
                    cp.SetAnswerText(_AnswerId, ReplaceFileName(_CompilerText.ToString()));
                }

                
try {
                    
if (_TestResult == Option.AnswerStatus.测试中 || _TestResult == Option.AnswerStatus.测试失败) {
                        Process[] p 
= Process.GetProcessesByName(_Sign);
                        
if (p.Length > 0) {
                            
if (!p[0].HasExited) {
                                
if (p[0].Responding) {
                                    p[
0].CloseMainWindow();
                                    p[
0].Kill();
                                }
                                
else {
                                    p[
0].Kill();
                                }
                            }
                            
if (_TestFile_Output.ToString().StartsWith(_TestOutput.ToString()))
                                _TestResult 
= Option.AnswerStatus.超时;
                            
else
                                _TestResult 
= Option.AnswerStatus.测试失败;
                        }
                    }
                }
                
catch { }
            }
            
else {
                _TestResult 
= Option.AnswerStatus.危险代码;
            }

            cp.SetAnswerStatus(_AnswerId, _TestResult);
//写入测试结果
            cp.SaveAnswerCode(_AnswerId, code);//写入提交的源代码
            /*try {
                if (_TestResult == Option.AnswerStatus.测试通过) {
                    using (StreamReader sr = File.OpenText(_CodePath)) {
                        cp.SaveAnswerCode(_AnswerId, sr.ReadToEnd());
                    }
                }
            }
            catch { }
*/
            DeleteTempFile();
//删除临时文件
        }

        
private void DeleteTempFile() {//删除临时文件
            Byte b = 0;
            
try {
                Thread.Sleep(
1000);//每一秒试删除一次
                if (File.Exists(_ExePath)) File.Delete(_ExePath); else b++;
                
if (File.Exists(_CodePath)) File.Delete(_CodePath); else b++;
                
if (File.Exists(_TextPath)) File.Delete(_TextPath); else b++;
            }
            
catch { }
            
if (b != 3) DeleteTempFile();//递归调用
            return;
        }
        
private bool IsCompilerSucess(string TextPath, string CppPath, String ExePath, int count) {
            
try {//看是否编译成功的函数
                using (StreamReader sr = new StreamReader(TextPath, Encoding.Default)) {
                    String input;
                    
bool f = true;
                    
while ((input = sr.ReadLine()) != null) {
                        _CompilerText.AppendLine(input);
                        
if (input.Contains(": error:")) {

                            _output.AppendLine(input);
                        }
                        
else {
                            
if (f && !input.StartsWith(CppPath))
                                _output.AppendLine(input);
                            f 
= false;
                        }
                    }
                    sr.Close();
                    
if (File.Exists(ExePath)) {
                        
return true;
                    }
                    
else {
                        _output.Insert(
0"编译出错:\r\n");
                        
return false;
                    }
                }
            }
            
catch {
            }
            Thread.Sleep(
1000);
            
if (count >= 300) {
                _CompilerText.Insert(
0"服务器响应超时或您选择的编译器不正确");
                
return false;
            }
            
return IsCompilerSucess(TextPath, CppPath, ExePath, count + 1);
        }
        
private string ReplaceFileName(string input) {
            input 
= System.Text.RegularExpressions.Regex.Replace(input, @"([A-Z]:[\\|\/][^:\*\?<>\|]+\.(txt|cs|cpp|c|vb|jsl|js|exe))|(\\{2}[^/:\*\?<>\|]+\.(txt|cs|cpp|c|vb|jsl|js|exe))"">", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            
return input;
        }
        
private void Process_Exited(object sender, EventArgs e) {//测试程序是否超时的判断
            if (_process.TotalProcessorTime.Milliseconds > _Time*1000) {
                
if (_TestFile_Output.ToString().StartsWith(_TestOutput.ToString()))
                    _TestResult 
= Option.AnswerStatus.超时;
                
else
                    _TestResult 
= Option.AnswerStatus.测试失败;
            }
        }
        
private void Test() {//进行测试
            string ExePath = _ExePath;
            
string TestPath = _TestPath;
            String input;
            
bool f = true;
            _TestEnd 
= false;
            _process 
= new Process();
            _process.StartInfo.WindowStyle 
= ProcessWindowStyle.Hidden;
            _process.StartInfo.UseShellExecute 
= false;
            _process.StartInfo.CreateNoWindow 
= true;
            _process.StartInfo.RedirectStandardInput 
= true;
            _process.StartInfo.RedirectStandardOutput 
= true;
            _process.StartInfo.RedirectStandardError 
= true;
            _process.StartInfo.FileName 
= ExePath;
            _process.Exited 
+= new EventHandler(Process_Exited);
            _process.OutputDataReceived 
+= new DataReceivedEventHandler(TestOutputHandler);
            _process.Start();
            _process.BeginOutputReadLine();
            _myMemory 
= (_process.PeakWorkingSet64 >> 10);//获取内存大小
            StreamWriter sortStreamWriter = _process.StandardInput;//设置异步读取流
            try {
                
using (StringReader sr = new StringReader(_Test)) {
                    
while (((input = sr.ReadLine()) != null)) {
                        
if (input.StartsWith("EOF"))//C/C++程序的结束(CTRL+Z)方式
                            if (_CompilerName.ToLower() == "c" || _CompilerName.ToLower() == "cpp")
                                sortStreamWriter.WriteLine(((
char)26).ToString());
                            
else//.net程序的结束(CTRL+Z)方式
                                _process.CloseMainWindow();
                        
if (input.StartsWith(">"))//测试的写操作
                            sortStreamWriter.WriteLine(input.Substring(1));
                        
if (input.StartsWith("<"))//测试的读操作
                            _TestFile_Output.AppendLine(input.Substring(1));
                    }
                }
                sortStreamWriter.Close();
                _process.WaitForExit();
                _TestEnd 
= true;
            }
            
catch {
                _TestEnd 
= true;
            }

            
if (_TestOutput.ToString() == _TestFile_Output.ToString())
                f 
= true;
            
else
                f 
= false;
            
if (_TestEnd && f)
                _TestResult 
= Option.AnswerStatus.测试通过;
            
else {

            }
            
if (_TestEnd && (_myMemory > _Memory))//内存消耗太大
            {
                _TestResult 
= Option.AnswerStatus.内存超量;
            }
            _process.Close();
            _process.Dispose();
            
if (f && _TestEnd) {
                _TestResult 
= Option.AnswerStatus.测试通过;
            }
            
return;

        }
        
void SaveTextFile(string Path, string text) {
            
using (StreamWriter sw = new StreamWriter(Path)) { sw.Write(text); }
        }
        
void DoCmd(string cmd) {//执行一条CMD命令的函数
            Process process = new Process();
            process.StartInfo.WindowStyle 
= ProcessWindowStyle.Hidden;
            process.StartInfo.UseShellExecute 
= false;
            process.StartInfo.CreateNoWindow 
= true;
            process.StartInfo.RedirectStandardInput 
= true;
            process.StartInfo.RedirectStandardError 
= true;
            process.StartInfo.FileName 
= "cmd.exe";
            process.Start();
            process.StandardInput.WriteLine(cmd);
            process.StandardInput.WriteLine(
"\r\nexit");
            process.Close();
            process.Dispose();
        }
        
bool IsTempExists(String TextPath, String CompilerString) {
            
int i = 0;
            
while (!File.Exists(TextPath)) {
                Thread.Sleep(
1000);
                i
++;
                
if (i > 178return false;
                
if (i % 30 == 0 && i > 10) {
                    DoCmd(CompilerString);
                }
            }
            
return true;
        }
        
private void TestOutputHandler(object sendingProcess,
            DataReceivedEventArgs outLine) {
            
int numOutputLines = 0;
            
if (!String.IsNullOrEmpty(outLine.Data)) {
                numOutputLines
++;
                
//Environment.NewLine +"[" + numOutputLines.ToString() + "] - " + 
                _TestOutput.AppendLine(outLine.Data);
            }
        }
    }

}

上篇:由成幻OnlineJudge学习如何做自己的Acm-Icpc在线评判系统-4.建立基本的网站类库
posted @ 2007-08-30 15:14  重典  阅读(3143)  评论(9编辑  收藏  举报