由成幻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 > 178) return 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.建立基本的网站类库

时间: 2024-09-16 02:04:46

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

成幻OnlineJudge源代码移至gforge

http://gforge.osdn.net.cn/projects/chswordoj/ 成幻Online Judge是一套免费的在线评判系统的开源程序. 按ACM-ICPC比赛规则进行开发. 可以用作ACM-ICPC比赛用站. 在下希望与对此感兴趣的同学一同开发此应用 QQ群:47369278(验证信息:OJ) SVN服务器:http://gforge.osdn.net.cn/svn/chswordoj/

成幻Online Judge 1.00 Beta 环境配置

要先下载成幻OnlineJudge下载地址 下载地址 OnlineJudge的运行需要.net 2.0 Asp.net ajax 1.0sql server 2005 express 支持 安装 请先安装此三个安装包在这里不多说了,安装方法网上教程极多. 安装本程序,安装本程序,例如安装到C:/onlinejudge/ 则文件夹内包含Compiler与web两个文件夹 IIS配置 在IIS中新建一个网站,将路径指向web文件夹 IIS网站属性 文档标签下的启动默认文档内容添加"Default.a

机器学习实例:深度学习如何做语音识别!

文章讲的是 机器学习实例:深度学习如何做语音识别,语音识别正在「入侵」我们的生活.我们的手机.游戏主机和智能手表都内置了语音识别.他甚至在自动化我们的房子.只需50美元,你就可以买到一个Amazon Echo Dot,这是一个可以让你订外卖.收听天气预报.甚至是买垃圾袋的魔术盒,而这一切你只需要大声说出: Aleax,给我订一个pizza! Echo Dot 在2015年的圣诞假期一经推出就大受欢迎,在亚马逊上面立刻售罄. 但其实语音识别已经存在很多年了,那为什么现在才成为主流呢?因为深度识别终

“上网”成中学生课余“最常做的事”

广州市首份中学生新媒体状况调研报告出炉 信息时报讯 (见习记者 林梦建 记者 梁健敏 通讯员 杜之芃) 昨日,<广州市中学生新媒体状况调研报告>(以下简称<报告>)新闻发布会在市第二少年宫举行.报告显示,上网已经成为中学生"课余生活最常做的事",半数学生无法忍受一周不能上网.相对应的是,与父母的交流则排名最后. "上网"成中学生课余"最常做的事" 记者了解到,这份报告是广州市青少年媒介素养教育中心的首份调研成果,自去年8月

幻腾是一家做智能家居公司主打套装产品

幻腾是一家做智能家居公司,主打产品是一个套装,包括智能灯,无线开关,环境控制器,可以监控空气质量温度湿度,还能远程遥控空调,最后还有一个网关提供联网服务. 很久之前我就接触过幻腾智能(Phantom)这家公司,个人很看好他们,之所以一直拖到现在才写,一方面是人家都融资了再不写实在过不去,另一方面是,我觉得自己不能清楚地介绍这家公司.这不能怪我,他们的 CEO 王昊自己也不能. 废话少说,幻腾是一家做智能家居的公司,但是它可能是你见过的智能家居中看起来最不智能的一家.幻腾官网上售卖的主打产品是一个

sum-如何把datagridview里的一列数字加和,运行显示内容无法强制转换成double型,怎么做?

问题描述 如何把datagridview里的一列数字加和,运行显示内容无法强制转换成double型,怎么做? 求代码 如何把datagridview里的一列数字加和,运行显示内容无法强制转换成double型,怎么做? 解决方案 我会了...........

phonegap-关于PhoneGap将andriod程序打包成IOS程序该怎么做?

问题描述 关于PhoneGap将andriod程序打包成IOS程序该怎么做? PhoneGap将andriod程序打包成IOS程序该怎么做?请知道的朋友给我说下具体步骤.多谢 解决方案 先在mac下搭建phonegap框架,再将js+html5等文件拷贝进去,修改网络连接bug和消息弹窗bug,其他的可能还会有些样式问题

成幻SNS(CHSNS#) foxblue 风格发布 清新自然

成幻SNS(CHSNS#) foxblue 风格发布 清新自然 CHSNS#风格安装方法 下载连接成幻SNS(CHSNS#) foxblue 风格发布 清新自然 关于CHSHS# 下载:http://www.eice.com.cn/download.ashx 演示:http://www.5field.com/ 社区:http://www.eice.com.cn/bbs/

成幻Online Judge 1.00 Beta 2 [2007.7.9 7:37]

升级内容 解决一些版本的操作系统的IIS服务兼容性问题. 增加了全Div/CSS可编辑性. 成幻Online Judge 介绍 成幻Online Judge是一套优秀的免费在线评判系统的整站程序. 按ACM-ICPC比赛规则进行开发. 可以用作ACM-ICPC 比赛用B/S站. 成幻Online Judge 1.00  用户许可 <成幻Online Judge>包括其所有文件.及抽象结构.一但用户安装.复制或以其它方式使用,即表示用户同意本协议的所有内容.如果您不同意这些条款和条件,请不要安装