# 判题服务器开发

判题服务器非常的简单，几乎无需做任何修改。采用TCP技术来通知判题机。

## 架构详解
测评模块仅提供了安全稳定的程序运行稳定，但是并不能判断程序是否通过，因此还要自己完成许多的逻辑工作。本系统的测评模块分为两部分，一部分是测评服务器，负责分发测评任务，另一部分是测评机，负责运行程序和提交测评结果。程序在运行过程中难免会消耗系统资源，如果只有一个判题程序在判题，如果判题时间较长，会导致后面的题目无法得到及时的反馈，但是如果太多判题程序同时运行，会导致系统资源消耗过大，导致前端和后台系统可能无法正确运行，所以要设计一个能够在多个机器上运行的判题程序，实现均衡负载功能，因此本OJ测评模块示意图如下：

![测评模块示意图](/img/faq/db3.png)

利用了数据库的事务管理，可使得高并发得以实现。用户相当于生产者，不断地向数据库提交待测评列表，测评服务器相当于一个消费者，不断的从数据库中获取未判提交列表，然后将这些题目分发到准备就绪的判题机，判题机收到判题任务后会进入忙状态，此时判题服务器不再向该判题机发送判题任务。当判题机判题完毕，会告诉服务器，可以继续判题。服务器再将该判题机纳入空闲列表。这样我们就能实现多个判题机同时运行，且这些判题机可以在任意的机器上运行，只需要通过TCP协议，链接到服务器上即可。同时服务器被设计成多线程的形式，在通过资源锁去控制并发的资源访问，使得多个判题程序能同时判题。 测评服务器，测评服务器使用Python开发，运行时会循环监听9906端口，一旦有测评机连上服务器，会新建一个线程，专门处理该测评机的消息。该线程首先会向测评机发送getstatus信息，测评机收到消息后会向服务器发送ok信号，代表已准备好判题。此时服务器会将该测评机纳入空闲列表。然后不断地循环发送getstatus信号，如果是not ok，代表非空闲状态，会将该测评机纳入非空闲列表。同时会有一个线程专门负责向数据库获取未判题列表，然后将未判题发放给空闲的判题机进行判题。


## 额外功能

由于历史原因和出于安全性的考虑，需要通过额外的程序来实现将比赛中的题目的权限设置为**可访问**，即将比赛中的题目访问权限设置为**私密**，这里将这个功能集成到了判题服务器的代码里。实际上这一部分可以独立出来运行。


## 源码解析

大概原理是这样的，这个判题服务器充当一个网关的功能，由他来拉取需要判题的列表，然后发送给各个服务器。这个判题服务器直接跟数据库进行通讯（直接把数据库当做中间件来用，比较方便）。用轮训的方式，不断地从数据库获取未判题列表，然后发送给各个判题机。当有判题机连入时，自动起一个线程来处理判题机的消息。判题机会不断地发送心跳包给判题服务器。

我真的写不动注释了！！！

[main.py](https://github.com/Linzecong/LPOJ/blob/master/JudgerServer/main.py)

[HDUVjudge.py](https://github.com/Linzecong/LPOJ/blob/master/Judger/VJudge/HDUVjudge.py)