在线oj项目分析:
想法很简单就是实现一个类似于牛客和力扣那样的在线编程系统。
这个系统主要是通过浏览器来实现客户端和服务器端的应答,在网络上进行数据的传输。
服务端和客户端交互流程:
上图是服务端和客户端进行交互的基本的流程,接着我们再对整个程序的服务端进行细致的划分,和各个模块的分析。
服务端模块划分:
服务器模块主要由oj_sever这一个模块来实现和客户端的交互的,背后负责支持的四个模块是,
试题模块:试题存储在服务器,当用户点击图标进行获取的时候我们再将试题的详细内容进行返回
编译运行模块:主要负责的是将用户提交上来的代码,进行编译运行,并且将最后的结果返回给用户
日志模块:贯穿整个过程,记录的是用户和服务端的交互信息,以及一些交互的记录,正确或者错误的记录,都会记录在日志中,可能用户在获取试题,或者服务端给返回数据的时候都有可能会发生数据上的错误。
工具模块:和日志模块差不多,都是贯穿整个服务器的,因为在我们的石头模块和编译运行模块,以及oj_sever模块都有可能会调用一些打印,或者其他的一些公用的代码,我们直接将这些代码封装起来。
所有的请求以及应答都是从oj_sever进行流入的,也是从oj_sever流出的。
接着我们将需求细分一下:
1.在浏览器中展示题目(oj_sever,试题模块)
2.客户可以选择题目进行作答(oj_sever,试题模块)
3.提交代码到后台(oj_sever)
4.针对客户端提交代码,进行编译(编译运行模块)
5.后台运行可执行程序(编译运行模块)
6.对结果进行打包(编译运行模块)
7.将结果返回给客户端(oj_sever)
oj_sever模块:
1.提供http服务(用户可以通过URL直接来访问我们的服务器),串联试题模块和编译运行模块
- 获取题目列表
- 提交选中的题目名称
- 提交题目代码和题目描述,代码的编译框
试题模块:
1.从文件当中加载题目(因为这里我没有把试题存储在MySQL中,是存储的文件中,所以我们对试题的获取也是从文件当中去获取的)
- 配置文件的格式(约定配置文件当中对题目的描述,题目的编号(id)题目的名称),首先映入用户眼帘的不是对每个题目的详细描述,而是题目的名字,id,以及难度,通过率,出现次数等这些简述性的信息。当然我们在这里会存入题目详细描述,也就是题目点开之后的,详细内容,在服务器的存储路径,我们的服务器是吧题目名称和题目描述分开存储的。这也就是我们所约定的格式。
- 加载所有的题目的配置文件,使用数据结构加载出来的题目的介绍信息,最重要的是:题目所在的路径一定要对。
- 针对每一道题目而言,需要按照给出的路径进行加载。(desc.txt题目描述信息(详细介绍这个题目,以及给出的例子)。header.cpp存放的是该题目所包含的头文件以及实现类(也就是我们一般在牛客做题的时候,她有时候会给出一些题目的部分代码,header里面存放的就是这部分代码)。tail.cpp存放的是我们的测试用例,以及main函数的入口 (也就是测试用户代码的例子))
2.提供获取整体题目的接口
- 给oj_server模块提供一个可以获取所有题目描述的接口,展示给用户
3.提供获取单个题目的接口
- 给oj_server模块提供一个可以获取单个题目描述的描述和作答接口,展示给用户。
4.编译运行模块:将用户提交的代码写道文件当中去,编译源码文件,编译成为可执行程序,并且运行
- 编译:将用户提交的代码写到文件当中去,编译阶段需要注意的是这里,不能直接让主进程去负责文件的编译,因为编译完成则进程退出,这里需要使用fork创建子进程,并且进行程序替换,让子进程去负责文件的编译源码文件,并且将编译的结果写到标准的输出文件中,或者标准错误中去
- 运行:如果代码走到运行阶段,说明一定编译出来的可执行程序,fork子进程,让子进程进行进程程序替换,替换成为编译出来的可执行程序。将程序的运行结果保存在标准输出或者标准错误文件中去。
工具模块:
- 提供时间戳服务,目的是区分,不同的用户提交的代码,将代码写进文件的时候,提供时间却来进行区分
- 提供写文件操作
- 提供读文件操作,需要提供对一行数据进行切割的接口
- 提供URL解码的操作
搭建简单的http服务器:
使用的是第三方库httplib.h使用的时候把他放到目录下,然后直接在头文件中包含“httplib.h”就可以了,库中给出了http的get,post等方法,设置监听和相应内容就搭建了简单的http服务器。
关于http协议进行简单的介绍:
http协议也就是应用层协议,应用层主要负责的是应用程序之间的数据沟通(指定的数据格式)
关于自定制的协议首先要解决的肯定是数据的粘包问题。
解决粘包问题的常见的方法有两种,
- 一种是探测接收,就是每次在接收数据的时候,先接收长度信息,再根据长度信息对接下来的数据进行接收。
- 一种是增加分隔符,也就是特殊字符,作为数据传输结束的标志,一般在文件的末尾 。
结构化传输:
序列化:将对象转化成为字节序列的过程,在传输数据的时候,按照数据结构对象当中变量的组织格式进行传输。
反序列化:将字节序列转化为对象的过程,在接收数据的时候,按照数据结构对象当中变量的组织格式进行接收。
常见的序列化和反序列化的种类:
json(javascript object Notation),键值对,数组,对象
jsoncpp提供了许多json接口供程序员使用。
json简介
http协议介绍:超文本传输协议,为啥叫超文本传输协议,是因为它不但可以传输文本,还可以传输图片之类的,所以叫超文本传输协议。
说到http首先介绍什么是http,有可能会问到URL,接着说到http的各个版本以及差
异,以及http协议的请求方法,以及使用的场景,在接着就是http请求格式和响应格式
(这里面有时候需要清楚详细的格式,需要知道一些请求头部的里面的键值对),以及常
见的状态码,以及代表的含义。可能会牵扯出https,以及ssl,问的比较多。
使用stringstream流来回复浏览器的http响应,做起来比C语言简单很多,主要是想说stringstream怎么用。