123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- //有思工作室编程类,用于Windows下面的C语言。
- //说明:nodejs很多命令默认是在linux下面写的,所以windows平台的信息有些不准确。
- //不能调用spawn命令,spawn是最原始的,不能设置超时时间,但spawn可以用数组,这点方便。
- //知识要点:CL为编译命令。[]数组中为参数选项
- // /nolog为不输出微软的标志。
- //哎,用GCC吧。等以后node稳定了再做windows版本。
- var fs = require('fs');
- var exec = require('child_process').exec, free;
- //var exec = require('child_process').exec, free = exec('CL', ['hello.c', '/nologo']);
- //var spawn = require('child_process').spawn, free = spawn('hello.exe', ['hello.c']);
- //var spawn = require('child_process').spawn, free = spawn('free', ['-m']);
- //------------------------------------------------执行PHP等解释型语言,解释执行的必须加chroot做沙箱------------------------------------------------------------
- //PHP语言
- exports.exephp = function (res, f,type) {
- //编译指令//生成gcc命令。
- //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。
- var cmd = "chroot ./output php ./userfiles/" + f + ".php";
- console.log(cmd);
- //解释性语言异步执行编译生成的命令为空。
- interpreLang(res, cmd , f, type);
- }
- //Python语言
- exports.exepython = function (res, f,type) {
- var cmd = "chroot ./output python ./userfiles/" + f + ".py";
- console.log(cmd);
- interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
- }
- //Nodejs语言
- exports.exenodejs = function (res, f,type) {
- var cmd = "chroot ./output node ./userfiles/" + f + ".js";
- console.log(cmd);
- interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
- }
- //Ruby语言
- exports.exeruby = function (res, f,type) {
- var cmd = "chroot ./output ruby ./userfiles/" + f + ".rb";
- console.log(cmd);
- interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
- }
- //Perl语言
- exports.exeperl = function (res, f,type) {
- var cmd = "chroot ./output perl ./userfiles/" + f + ".pl";
- console.log(cmd);
- interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
- }
- //Lisp语言
- exports.exelisp = function (res, f,type) {
- var cmd = "chroot ./output clisp ./userfiles/" + f + ".lisp";
- console.log(cmd);
- interpreLang(res, cmd, f, type); ; //解释性语言异步执行编译生成的命令为空。
- }
- //解释性语言统一调用函数
- interpreLang = function (res, cmd,f, type) {
- var output = ""; //最终返回的错误信息,警告信息,执行成功信息以及生成的exe的执行信息。但如何区分?
- //解释性语言异步执行编译生成的命令为空。
- usexefile(res, cmd, "", f, output, type, interpreLangAsyn);
- }
- interpreLangAsyn = function (res, output,f, acmd, type) {
- output = "运行环境Linux+" + type + "语言:\n" + output;
- res.end(output); //php很简单,没C复杂
- }
- //------------------------------------------------执行Gcc Net Mono等编译型-----------------------------------------------------
- //执行Net和Mono
- //mono还需要 /proc才能运行,需要把/proc mount到 chroot目录
- //首先在choot目录下建立文件夹 /proc。
- //mount proc ./proc -t proc
- exports.exenet = function (res, f,type) {
- //Mono编译太慢,需要调整时间为5秒
- f = './output/userfiles/' + f; //给文件加上目录名
- var cmd = 'mcs ' + f + '.cs';
- //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。异步执行的命令
- var acmd = "chroot ./output mono ./userfiles/" + f.slice(19) + ".exe";
- execomplie(res, f, cmd, acmd,type);
- }
- //执行Gcc
- exports.exegcc = function (res, f,type) {
- //编译指令//生成gcc命令。
- f = './output/userfiles/' + f; //给文件加上目录名
- var cmd = 'gcc ' + f + '.c' + ' -o ' + f + '.exe';
- //再执行此执行文件,chroot是让命令执行在沙箱中。沙箱命令需要去除目录标识。异步执行的命令
- var acmd = "chroot ./output ./userfiles/" + f.slice(19) + ".exe";
- execomplie(res, f, cmd, acmd,type);
- }
- //------------------------------------------------------编译型命令封装-------------------------------------------
- //res是传递的http参数,f是文件,c是需要执行的编译命令,as是编译成功后执行可执行的exe文件命令
- execomplie = function (res, f,cmd,acmd,type) {
- //编译指令//生成gcc命令。
- var output = ""; //最终返回的错误信息,警告信息,执行成功信息以及生成的exe的执行信息。但如何区分?
- usexefile(res, cmd, acmd, f, output,type, execcompileAsyn);
- }
- //执行Gcc命令回调函数。参数1为执行gcc的返回数据,参数f为文件名。acmd是执行编译成功后可执行文件的命令
- execcompileAsyn = function (res, output, f,acmd,type) {
- //如何判断编译成功呢?暂时采用是否生成了可执行文件的方式。如果采用这种方式,好像windows平台也能做,但有问题,生成成功后再次生成即使错误也会判断成功。
- //对了,同时判断是否有错误输出就OK了。前台判断好还是后台判断好?
- //加Sync表示同步,此处异步好还是同步好呢?
- if (builderr(output)) res.end(output);
- else {
- if (fs.existsSync(f + '.exe')) {
- output += "运行环境Linux+" + type + "语言:\n";
- //再执行此执行文件,把异步命令作为执行命令,原来的异步命令为空。
- usexefile(res, acmd,"", f, output,type, execexeAsyn); //异步执行生成的exe文件。
- }
- }
- }
- //执行C语言可执行文件回调函数
- execexeAsyn = function (res, output, f) {
- //删除执行文件,准备下次运行。此处不好整理逻辑。
- res.end(output);
- }
- //判断编译是否发生错误,如果发送错误,则输出true,否则输出false
- builderr = function (output) {
- var z = output.replace(/\r\n/g, '\n').split('\n'), i;
- for (i = 0; i < z.length; i++) {
- if (z[i].indexOf('标准错误输出') > -1)
- return true;
- }
- return false;
- }
- //--------------------------------------执行控制台命名封装---------------------------------------
- //判断用户是否输出了加大的文字量,如果用户恶意输入,给他提示,结束程序。
- largeoutput = function (res,output) {
- if (output.length > 10000)
- res.end("哥们,别开玩笑!\n"+output);
- }
- //雨云科技执行文件函数,cmd是nycodex.com命令,callback是执行完毕后的回调函数
- usexefile = function (res, cmd, acmd, f, output,type, callback) {
- //var output = ""; //输出,因为stderr或者stdout会触发多次,用一个变量循环,为啥要触发多次,以后研究。
- //-Wall 把所有编译警告全部显示。-o指定输出目录
- //free = exec('gcc -Wall ./output/hello.c -o ./output/h.exe',
- free = exec(cmd, {
- encoding: 'utf8', //编码设置
- //encoding: null, //编码设置
- timeout: 8000, //超时时间设置。
- maxBuffer: 200 * 1024,
- killSignal: 'SIGTERM',
- cwd: null,
- env: process.env //windows环境设置或者linux环境设置,好像不成功
- });
- // 捕获标准输出并将其打印到控制台
- free.stdout.on('data', function (data) {
- //console.log('标准输出:\n' + data);//data != "\n" ? output += "标准输出: " + data : output += data; //给输出前面加上中文标示,便于学生理解
- output += data;
- //res.write(data);
- //if(output.length>1) res.end(output);
- //largeoutput(res, output);
- //res.end("AAAAAA");
- });
- // 捕获标准错误输出并将其打印到控制台 //console.log('标准错误输出:\n' + data);
- free.stderr.on('data', function (data) {
- (data != "\n"&&data != "\r") ? output += ("标准错误输出:" + data) : output += data; //给输出前面加上中文标示,便于学生理解。
- });
- // 注册子进程关闭事件 //console.log('子进程已退出,代码:' + code); console.log(output);
- free.on('exit', function (code, signal) {
- largeoutput(res, output);
- if (callback) callback(res, output, f,acmd,type); //如果有定义回调函数,则执行回调函数。
- });
- //free.stdin.write("4\n");
- //C语言处理标准输入,非常麻烦,暂时留在这里。这应该封装为一个函数。首先用resume恢复以前的进程,不过首先需要找到该进程。
- //free.stdin.resume(); //这句话是为了不让控制台推出
- //free.stdin.on('data', function (data) {
- //console.log('标准输出:\n' + data);//data != "\n" ? output += "标准输出: " + data : output += data; //给输出前面加上中文标示,便于学生理解
- //free.stdout.write('标准输入:' + data);
- //free.stdin.emit('end');
- //output += "本系统暂时不支持scanf输入语句,有高手能实现吗?请在意见反馈中联系我们,谢谢";
- //res.end(output);
- //free.stdout.write('data:'+data);
-
- //});
- //free.stdin.on('end', function () {
- //if(output.length>1) res.end(output);
- //output+="input end";
- //free.stdout.write('end');
- //output += "本系统暂时不支持scanf输入语句,有高手能实现吗?请在意见反馈中联系我们,谢谢";
-
- //});
- }
|