基于Linux系统调用使用php实现一个在线编译运行C语言程序的系统
2011-04-11 21:42
1181 查看
前段时间给学校做一个在线练习C语言程序和C语言考试的系统,服务器架构是LAMP的。因为其他的都没什么好多的,要实现在线编译只要exec()函数直接调用gcc进行编译就行了,
这里解释一下命令:$filename是你的C语言源程序的地址,-o指定生成可执行文件名,2>compile_result.txt是将编译结果输出到compile_result.txt文件里面去(gcc的编译结果是输出到标准错误2的而不是标准输出1)分号是本语句结束,下一个语句是编码转换的命令,因为我要返回的是gb2312编码的字符,所以就将之前的编译结果文件转换成GB2312编码放到compile_res.txt里面去了。这里实现其实很多余,因为你完全可以就enconv -L zh_CN -x UTF-8 filename直接搞定,但是蛋疼的是服务器居然没有这个工具。没办法之下才用的iconv。如果客户要的就是UTF-8编码的话,那直接 2>&1就OK了,都不用临时文件咯~
接下来是要在客户端上运行我们的C程序,并且将程序的输出输出到浏览器上。(并且能够读入用户端在浏览器输入的输入)这才是我们的重头戏!
首先,我们的实现还是基于临时文件和系统调用的基础之上实现的。不错如果要把用户的输入给弄到程序里面去的话,仅仅这样是不行的,下面我来说下我的实现方法:
主要的代码就是这样,这里的run_me程序是一个用C语言写的,将用户程序作为一个子进程运行,并且将用户程序的标准输入关闭,通过管道把input.txt的内容输入到用户程序中。(这里需要写过Linux下的进程最后输出运行结果的操作。
run_me的源代码如下:
如果熟悉在Linux下操作的朋友门一定觉得我上面的操作有点多余,直接就运行./prog_name < input.txt不就完了么?呵呵,是这样的,但是你要想到,如果用户是一个死循环程序,那么,你的服务器估计活不了太长的时间,如果只在系统层面limit对系统做限制,又不能保证大量用户同时使用这个系统。所以我才自己手动实现了一个重定向操作,并且加入了只让用户程序执行10毫秒的元素,这样就解决问题了~呵呵,如果有更好的方法希望大家推荐一下。也欢迎大家指出我的错误和问题。有什么不明白的地方也可以说出来大家讨论讨论~~
$compile_str = "gcc ".$filename." -o ".$prog_name." 2>"."compile_result.txt;iconv -f UTF-8 -t GB2312 "."compile_result.txt -o compile_res.txt";
这里解释一下命令:$filename是你的C语言源程序的地址,-o指定生成可执行文件名,2>compile_result.txt是将编译结果输出到compile_result.txt文件里面去(gcc的编译结果是输出到标准错误2的而不是标准输出1)分号是本语句结束,下一个语句是编码转换的命令,因为我要返回的是gb2312编码的字符,所以就将之前的编译结果文件转换成GB2312编码放到compile_res.txt里面去了。这里实现其实很多余,因为你完全可以就enconv -L zh_CN -x UTF-8 filename直接搞定,但是蛋疼的是服务器居然没有这个工具。没办法之下才用的iconv。如果客户要的就是UTF-8编码的话,那直接 2>&1就OK了,都不用临时文件咯~
接下来是要在客户端上运行我们的C程序,并且将程序的输出输出到浏览器上。(并且能够读入用户端在浏览器输入的输入)这才是我们的重头戏!
首先,我们的实现还是基于临时文件和系统调用的基础之上实现的。不错如果要把用户的输入给弄到程序里面去的话,仅仅这样是不行的,下面我来说下我的实现方法:
$input = $_POST['input']; //取得用户输入 $fp=fopen($path.'input.txt','w+');//打开文件 if(!$fp) //错误处理 { echo "打开文件失败"; echo $path.'input.txt'; } $temp=fwrite($fp, $input); //用户输入写入文件 fclose($fp); if(chdir($path) == false){ //进入目录执行命令 echo "进入目录失败:"; } if(!chmod("run_me", 0777)){ //run_me程序我们接下来讲 echo "改变文件权限失败"; } $cmd_str = "./run_me ".$prog_name." input.txt";//命令语句 echo "运行结果:"; exec($cmd_str, $arr); //执行命令将输出结果放到数组arr里面 for($i = 0; $i < count($arr); $i++) { echo $arr[$i]."/n"; }
主要的代码就是这样,这里的run_me程序是一个用C语言写的,将用户程序作为一个子进程运行,并且将用户程序的标准输入关闭,通过管道把input.txt的内容输入到用户程序中。(这里需要写过Linux下的进程最后输出运行结果的操作。
run_me的源代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> void get_file_buf(char (*buf)[81], char *filename)//取得文件的缓存到数据缓冲区 { FILE *fp; int i = 0; if( (fp = fopen(filename, "r")) == NULL) { perror("can't open the file"); exit(EXIT_FAILURE); } while(fgets(buf[i], 81,fp) != NULL) { i++; } } int main(int argc, char **argv) //主函数 { int file_pipe[2], i = 0; //定义管道 pid_t fork_result; //fork结果 char row_input[100][81]; //定义用户输入缓存大小 char progname[255]; //定义程序名称 char *filename; if(argc > 3){ printf("usage :run_me $programname $filename"); exit(EXIT_FAILURE); } //Initiaze buffer for(i = 0; i < 100; i++) { memset(progname, '/0', 81); memset(row_input[i],'/0',81); } // strncat(progname, "./", strlen("./")); //这里将用户程序加入./指定当前用户 strncat(progname, argv[1], strlen(argv[1]));//链接参数传递的程序名称 if(argc == 2) { system(progname); return 0; } filename = argv[2]; //输入文件名 get_file_buf(row_input, filename); i = 0; if(pipe(file_pipe) == 0) //管道初始化 { fork_result = fork(); //分叉程序生成子进程 if(fork_result == (pid_t) -1){ //错误处理 perror("Fork failure"); exit(EXIT_FAILURE); } if(fork_result == (pid_t) 0 ) //子进程操作 { close(0); dup(file_pipe[0]); close(file_pipe[0]); close(file_pipe[1]); execlp(progname, progname, NULL, NULL); exit(EXIT_FAILURE); } else //父进程操作 { close(file_pipe[0]); while( *(row_input[i]) != '/0')//向子进程写入缓冲流 { write(file_pipe[1], row_input[i], strlen(row_input[i])); i++; } close(file_pipe[1]); usleep(10000); //只让程序执行10毫秒 execlp("killall", "killall", argv[1], NULL);//结束子进程 } } return 0; }
如果熟悉在Linux下操作的朋友门一定觉得我上面的操作有点多余,直接就运行./prog_name < input.txt不就完了么?呵呵,是这样的,但是你要想到,如果用户是一个死循环程序,那么,你的服务器估计活不了太长的时间,如果只在系统层面limit对系统做限制,又不能保证大量用户同时使用这个系统。所以我才自己手动实现了一个重定向操作,并且加入了只让用户程序执行10毫秒的元素,这样就解决问题了~呵呵,如果有更好的方法希望大家推荐一下。也欢迎大家指出我的错误和问题。有什么不明白的地方也可以说出来大家讨论讨论~~
相关文章推荐
- linux下使用系统调用实现进程后台运行
- 如何来实现一个Linux内核的系统调用(基于tiny4412开发板)
- 如何来实现一个Linux内核的系统调用(基于tiny4412开发板)
- java开发系统内核:使用一个中断实现多个API调用
- 基于PHP实现一个简单的在线聊天功能
- PHP使用ffmpeg实现视频截图(Linux系统和windows系统)
- Mahout分布式运行实例:基于矩阵分解的协同过滤评分系统(一个命令实现文件格式的转换)
- Linux之使用内核模块增加一个系统调用
- 一个设想:基于colinux,去厚重虚拟化,共盘直接文件系统安装运行的windows,linux
- 树莓派1代·添加一个linux系统调用·编译内核
- 问题阐述: 本人使用mini6410开发了一个sqlite数据库的程序,在mini6410的linux系统下已经能够成功运行了。因为Android使用的也是linux内核,所以我想当然的认为按照同样
- 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用(Linux)
- 使用 Ansible 在树莓派上构建一个基于 Linux 的高性能计算系统
- 用c语言程序实现系统的cp命令 在linux下调用syscalls.h头文件
- Linux系统下使用XHProf和XHGui分析PHP运行性能
- 使用 Ansible 在树莓派上构建一个基于 Linux 的高性能计算系统
- linux两个版本 php命令使用其中一个版本运行
- 在i386平台Linux 2.6 上实现一个系统调用
- 如何使用jQuery+PHP+MySQL来实现一个在线测试项目
- 如何使用jQuery+PHP+MySQL来实现一个在线测试项目