C#-JudgeSystem判题系统-判题系统

运行环境: vs2013

框架: .net4.5

上一次实验已经完成了判题核心的封装,接下来就是通过服务器后台调用判题系统对客户端传来的数据进行判断

根据前面的一些测试我们建立新的解决方案来实现完整的判题系统

首先第一步我们先确定客户端和服务器的交互流程

客户端的数据有三个:源代码,输入,输出

这时候到底怎么传到服务器的,有两个方法,一个是一次性传输,一个是分三次传输

一次性传输的话就要面临怎么切割这三种数据,必须定义一个分割符,而且数据也要面临转义的问题,到了服务器也需要进行解译,这样会消耗一定的资源

但到底这三个数据是不是一定要一次性传输呢?其实并不用,因为这三个数据作用于不同阶段并且可以单独分割开来,所以分三次传输其实是可以的,并且每个阶段都可以根据回传来判断判题的状态,出现错误是可以减少后面两次的传输,节省一定的宽带与内存

server              cilent

                        send:源代码

read:源代码

compile:源代码

send:编译结果

                        read:编译情况

                        如果成功

                        send:输入

read:输入

run:输入

send:运行情况

                         read:运行情况

                         如果程序成功运行结束未超时

                        send:输出

read:输出

比较输出

send:结果

                         read:结果

close                 close

做好流程设计后开始编码程序

由于把输入输出分离,所以类库接口需要改变适配,类库改变的成本较低,所以不采用改变调用

C#-JudgeSystem判题系统-判题系统_第1张图片

分割实现

C#-JudgeSystem判题系统-判题系统_第2张图片

第一步服务器读取源代码

编译,根据返回值来发送结果

C#-JudgeSystem判题系统-判题系统_第3张图片

如果编译通过就继续向客户端读取测试输入

考虑到部分程序不需要输入所以接收到\r\n则当作无输入

所以不允许程序只那\r\n来作为测试输入,事实上也没什么意义这样的输入

虽然可以再增加一次交互来确定程序是否提供无输入测试,但这里并没有做这个操作

C#-JudgeSystem判题系统-判题系统_第4张图片

如果能拿到结果不超时,则向客户端读取结果进行匹配

下面建立一个测试用的客户端项目

C#-JudgeSystem判题系统-判题系统_第5张图片

客户端三次大循环往服务器发送消息

运行服务器,监听8080端口

Unnamed QQ Screenshot20150804171013

然后打开客户端进行连接

C#-JudgeSystem判题系统-判题系统_第6张图片

然后打开客户端进行连接

C#-JudgeSystem判题系统-判题系统_第7张图片

设置了30秒的超时

过了30秒客户端无发送数据的话,会主动关闭连接

C#-JudgeSystem判题系统-判题系统_第8张图片

再次启动新的客户端测试

C#-JudgeSystem判题系统-判题系统_第9张图片

语法错误的测试,会返回客户端1,代表false

C#-JudgeSystem判题系统-判题系统_第10张图片

没有语法错误编译通过的则返回0

C#-JudgeSystem判题系统-判题系统_第11张图片

测试第一部分通过则测试第二部分,输入部分,源程序应该输入两个数字空格,输出两个数字的和,但测试中我只输入一个数字,5秒后程序还没结束则返回false,服务器端可以看出原因是超时

启动失败比较慢测试出来,还有一种可能是正常非正常退出

C#-JudgeSystem判题系统-判题系统_第12张图片

虽然输入是正确的,但是程序退出值不为0,当作错误处理,返回false

最后测试正确输出得到结果

C#-JudgeSystem判题系统-判题系统_第13张图片

虽然输入正确也能得到结果了,但是不匹配,则返回false

C#-JudgeSystem判题系统-判题系统_第14张图片

测试1+3=4可以通过,最后返回true,证明编译通过且结果正确

到此为止就完成了服务器程序的大部分功能了,而且异常机制与超时机制也可以保证服务器的运行

然后为了保证服务器的并发编译稳定性,测试程序将改成自动多线程并发执行判断结果是否通过

为了能遍历并发各种各样的情况,我把三个步骤的正确与错误做法写出用来做组合处理

C#-JudgeSystem判题系统-判题系统_第15张图片

第一步,错误是少一个;分号

C#-JudgeSystem判题系统-判题系统_第16张图片

第二步提供一下错误的输入

C#-JudgeSystem判题系统-判题系统_第17张图片

第三部提供错误的结果

C#-JudgeSystem判题系统-判题系统_第18张图片

check返回值,读取服务器的返回,0为true,1为false,每进行一步操作都要check一次看是否能匹配那次操作的返回值,不对应则为一次bug

线程函数已三个数字启动,做成字符串的形式

000代表三步为true

111代表第一步错误

011代表第二步错误

001代表第三步错误

C#-JudgeSystem判题系统-判题系统_第19张图片

启动线程遍历四种情况,每10次启动线程读取一次bug次数

并发间隔是500ms

C#-JudgeSystem判题系统-判题系统_第20张图片

启动线程遍历四种情况,每10次启动线程读取一次bug次数

并发间隔是500ms

C#-JudgeSystem判题系统-判题系统_第21张图片

放置启动700次线程,理论上大部分线程都完成操作,没有发现任何的bug

后来将并发速度提升到100ms

程序运行非常快,cpu占用也到了80%左右

C#-JudgeSystem判题系统-判题系统_第22张图片

短时间运行下是没有任何的错误,服务器和客户端都没有崩溃

在进行上千次运算后

任务管理器中并没有发现游离的进程

C#-JudgeSystem判题系统-判题系统_第23张图片

在测试路径下发现大量的编译程序

该测试证明,服务器系统是稳健的,高并发的,并且能提供准确返回值的系统

当然这次测试是在可靠的传输环境下实现的,而在不可靠环境下或者网络环境较差的情况下,服务器只能依赖于自身的超时检测,在30秒内客户端无消息则关闭连接

在完善服务器的情况下,我们继续实现客户端的GUI化

GUI部分简单复用一下原来第一个实验的代码,但需要增加输入输出框

简单修改一下

C#-JudgeSystem判题系统-判题系统_第24张图片

里面一下控件有必要的写上变量名

C#-JudgeSystem判题系统-判题系统_第25张图片

所幸的是textbox控件自带换行的功能,这个可以省去类似控制台的添加换行符的复杂问题,只需要将原来的控制台的程序代码复制一下,需要的数据改成从gui获取

C#-JudgeSystem判题系统-判题系统_第26张图片

点击ui上面的判题按钮会触发judge函数

完成后我们测试一下运行的效果

打开程序

C#-JudgeSystem判题系统-判题系统_第27张图片

如果在没有源代码和输出的内容条件下,判题是不允许的

C#-JudgeSystem判题系统-判题系统_第28张图片

无输入的判题(任意输入)

C#-JudgeSystem判题系统-判题系统_第29张图片

服务器关闭的情况下

C#-JudgeSystem判题系统-判题系统_第30张图片

会显示服务器连接错误

C#-JudgeSystem判题系统-判题系统_第31张图片

源代码少一个分号,显示编译错误

C#-JudgeSystem判题系统-判题系统_第32张图片

不进行正确输入,服务器会显示超时处理,客户端会显示错误的输入

C#-JudgeSystem判题系统-判题系统_第33张图片

输入正确则判断结果,结果不正确则输出错误的结果

C#-JudgeSystem判题系统-判题系统_第34张图片

结果正确,自然进入接受状态

对此已经完成客户端的基本功能,当然再错误的输入或者在算法复杂度较高的运算中,服务器未能够做出及时的相应,这时候就要做线程处理可以避免程序在等待过程中表现的卡死现象,暂时不去实现这是优化性的功能,到此整个实验已经进行完毕

通过最后一个综合实验,整合每个实验的内容,完善服务器功能与客户端的使用,在实验过程中,对于服务器的稳健性等做了更深层的探索,而客户端部分还有一些线程级别的优化并没有进行,有待实现,从开始的设计到各个部分的调整,也体会到知识综合应用的重要性,在这一次实验中并没有过多新知识的掌握,更重要的是接口与测试部分的实现

你可能感兴趣的:(多线程,server,C#,编译,判题系统)