View Code? Open in Web Editor
NEW
This project forked from mufeng964497595/onlinejudge
使用JSP实现的OJ系统,支持用户提交C、C++和Java语言的代码
C++ 2.89%
Shell 0.09%
Java 28.17%
CSS 5.29%
JavaScript 63.55%
onlinejudge's Introduction
- 首先是一定要感谢HUST OJ的大大们的,阅读源代码的过程中经验值飞增。
- 这是一个使用JSP实现的简单的OJ,对数据库的操作均通过调用存储过程和激发触发器来实现。
(所以最后写出来的存储过程好多啊。。。。)
- 数据库的信息,例如地址啊用户名啊密码啊没有写在Java类里,而是写了一个叫做databaseInfo.xml的文件(在web/WEB-INF路径下),然后用一个监听类来获取这个文件的绝对路径地址,在ConnectionDao这个类里读取出相应的信息,这样移植起来就方便啦,不给源码只给编译后的class文件的话也可以修改数据库。
- 判题的隔离问题使用Docker来实现,下载了一个ubuntu镜像,然后自己在镜像中安装gcc, g++, java, 并新建一个弱权限的用户。把修改后的镜像保存起来,在判题时进入docker使用弱权限用户运行程序。
- JSP只负责前端和处理用户提交的信息。用户提交代码后,JSP将信息写入数据库,提交状态设置成queueing,之后就不需要管了,全权交给Linux端去弄。
- Linux端有两个程序,一个是轮询程序(polling.cpp),另一个是判题程序(judge.cpp),两个程序的参数都是通过命令行传参的,因此我又另外写了两个shell脚本(startup.sh和judge.sh)去执行程序。
- Linux端C++与数据库的连接是使用mysql-connector-c++实现的。
- 使用 nohup ./startup.sh $ 命令可以让进程在后台运行,退出终端后程序也不会终止。这个脚本会执行polling程序,并将相关的参数以命令行的形式传进程序中。polling程序是一个死循环的轮询程序。程序获取参数后,会连接数据库,然后调用存储过程将数据库中所有状态为queueing的提交按提交时间排序,先提交的排前面,全部放进队列里,然后断开数据库连接。如果队列不为空,就将数据逐个拿出来,把代码写入到文件中后,fork()一个子进程去启动judge.sh脚本,父进程就用waitpid()等待子进程结束。一直到队列为空。之后就sleep一秒中,然后继续刚才的操作,查询数据库的信息并判题。
- judge.sh文件做两件事,一件是把编译后的judge程序拷贝到所要隔离的目录下(当初写这个是怕用户程序把目录下所有文件都删了,导致后续无法判题,现在想想,似乎删不了正在执行的程序,不过这样做了之后,我在修改judge文件之后,就不需要再手动拷过去了2333),另一件事是运行Docker,并在Docker中运行judge程序。
- judge程序是判题程序。首先是通过传递的参数编译用户的源代码,如果编译出错,则向数据库写入系统错误或编译错误及错误信息;否则,开始判题。判题时,通过链接数据库获取题目限制的时间和内存,并读取所有的输入数据、输出数据。对于每组数据,先将输入数据写入到当前工作目录下的文件中,然后fork()一个子进程去运行代码,并用freopen重定向输入数据为刚才保存的文件、输出为文本文件,stderr也重定向为文本文件。父进程用ptrace监控该子进程,若达到超时、超内存、状态异常等情况,则改变判题结果为对应的状态,并结束子进程。若子进程正常结束,则比对一下用户输出与该组输出数据。判题直到数据全跑完,或者判题结果不再是AC,就可以结束了。最后就是更新数据库结果了。(PS:Docker默认不能使用ptrace,这个bug调了好久,最后才发现是Docker的问题。。。在启动Docker之前,加入启动选项 --cap-add=SYS_PTRACE就行了。)
- 运行时间的获取可以直接有usage得到,而内存大小就搞不定了。通过研究HUST OJ的源代码,发现进程在运行的时候,会产生 /proc/pid/status这个文件(pid就是该进程的pid),里面记录了挺多内存信息的,且单位是KB,需要自己转一下,那么问题就变成文件读取了。(这是C和C++的,JAVA的需要到另一个地方看,应该是因为JVM的关系。)
onlinejudge's People
Contributors