一、项目介绍
项目背景:我自己比较喜欢点外卖,所以就自己做了一个点餐系统
要实现客户需求:用户使用浏览器,以 ip 地址加端口号的形式,进入到点餐页面,把选好的菜品,提交到服务器,进行下单
主要工作:服务器的开发,服务器分为两个部分,web 服务器和数据的存储,web 是通过 cpp-httplib 库开发出一些对应的接口供客户端调用,当客户端请求的数据是合法的时候,会涉及存储部分,主要有数据库的访问,查询,修改和删除等操作
技术: HTTP 协议、TCP 协议、json 格式来组织数据,以及一些前端技术,比如 html css ,ajax 向服务端发送数据等等
二、项目的架构
- 服务端
- 商家客户端
- 用户客户端
首先自定义菜品的信息 -->加载到服务器 --> 服务端给用户客户端提供了一些服务功能,比如可以查看菜品,支持下单,给商家客户端提供了查看订单,修改订单等操作
数据存储
1、为了能够让客户看到菜品,商家需要把菜名提前录入到服务器数据库中
2、数据库用了两张表,菜品表和订单表,订单表中的菜名是作为菜品表的外键,每张表也都有自增主键约束,来保证唯一性
3、启动服务器,自动会连接数据库,实例化对象(两张表,httplib 库中的 server 对象)
4、客户端会发送数据的请求,这个要根据具体业务来说
5、数据传输
5.1 请求采用 http 协议,底层是 tcp 协议保证传输的可靠性
5.2 这个请求会被放在 http 协议的正文中,通过 ajax 提交给后台
5.3 后台是通过开源的 httplib 库获取到这个请求
5.4 获取到请求后,服务器根据对应的业务来操作不同的数据表,操作完成后返回客户端
5.5 返回的数据是 json 串,客户端页面获取到数据后,进行渲染
三、业务流程
当客户端想要查询菜品的时候,会发生 xx 请求,数据格式是xx,cpp-httplib 拿到这个 url 会自动调用回调函数,回调函数有两个参数
第一个是请求,第二个是响应,请求是浏览器提交过来的数据,里面包含头部信息,空行,和正文信息,在请求当中拿到 body 部分调用 json 函数 prase 来解析字符串,可以把传递上来的 key 和 value 区分开来,存储在json格式组织起来,这个时候需要判断是否是正确合法的数据,如果是的话,然后把它交给处理函数,处理函数会获取数据库中的菜品信息,以及查询和保存起来,使用一个指针传递出去,传递出去之后,要做的事情就是将 json 格式的数据转换为 json 串返回给客户端
当客户用浏览器去访问的时候,首先访问的是静态服务器 index.html 界面,在 index 界面中使用 ajax 会给服务器发送一个get 方法的请求,获取所有的菜品,返回的是一个 json 串数据,数据里面主要有菜品名称和价格,html 页面拿到 json 格式数据后,会渲染到页面里,从而页面就可以展示菜品和价格
1、查看菜品
客户端:客户端想要获取所有的菜品信息,会发送请求数据,请求方法是 get 请求,url 是/dish
服务器端:监听到这个请求后,会调用业务函数,也就是操作数据库,查询数据库中的菜品表,然后把它取出来,用到遍历结果集函数,把遍历的数据用 json 格式组织起来,数据库操作完后,然后使用一个指针传递出去,然后到主流程中,组装一个 json 数据,调用 set_content 返回给客户端一个 json 串,客户端页面接收到,保存在了一个列表中,然后使用循环遍历,渲染到页面中
2、提交下单
客户端:客户端会给服务器发送数据请求,请求方法是 post 类型,url 是/order ,然后会构造一个 JavaScript 对象,里面包含下单的时间,下单的桌号,以及下单了哪些菜品,调用 stringify 把它转换为字符串,这个是存放在主体部分的,调用 ajax 把它发送给服务器
服务器端:接收到这个请求后,首先会取出请求参数中的 body 部分,然后解析到 json 格式的数据中,接着需要判断数据的合法性,如果合法则调用业务函数,也就是操作数据库中的订单表,进行插入数据,如果插入成功,则构造正确的响应,比如状态码为 200,解释信息为 true ,最后转换为 json 串后,调用 set_content 函数返回给客户端
四、项目技术难点,遇到的问题
前端
我之前完全不懂前端,因为项目要有一个客户端界面,我研究了一下前端, vue 和 ajax ,如何构造请求,如何发送,然后收到数据,怎么渲染
项目启动后,第一天可以访问到,第二天访问就会出错
数据库的默认连接为 8 小时
-
解决办法1:我可以在项目开启一个线程,然后每隔一段时间去检测数据库是否断开,如果断开就重新进行连接,MySQL 客户端也提供了一个库去检测连接是否断开,当然也可以多建立几个连接,每次只获取一个,一个线程循环遍历连接,如果有哪些连接断开,就进行重连
-
解决办法2:直接把数据库的默认连接时间改大一点,配置参数
五、项目有哪些优缺点
优点
支持并发,客户端的访问都是安全的,同一时刻最大并发数为5,但是也可以通过 httplib 底层来调整 listen 的第二个参数
CPU 占用率也不高 (top 命令查看)
缺点
没有使用一些缓存等,访问的效率可能不是很高
六、项目哪些功能还可以扩展?
- 支持订单的追加
- 支持多商家用户管理
七、项目如何编译
通过 Makefile 进行自动编译
我项目中使用到了 json 开源库,链接了 jsoncpp 开源库,并且使用到了 MySQL C客户端提供的动态库,所以也会去链接 MySQLClient 库,另外也链接了一个多线程库,在 cpp-httplib 中使用到,当浏览器发送一个请求的时候,httplib 库底层创建出来一个线程,然后去处理这个请求
八、怎么保证客户请求的同步互斥
比如来了10个请求,怎么保证访问的安全性
答:MySQL 客户端提供的接口,比如执行 mysql_query ,遍历结果集函数,这些都是线程安全的,我的代码也没有使用互斥锁这些技术,因为也不需要做额外的工作
八、数据库
使用的数据库版本,5.5.60 MariaDB
查看方法1:直接连接到数据库可以查看
查看方法2:使用命令 select version();
查看
Maria DB 和 MySQL 的区别?
1、MaiaDB 是 MySQL 源码的一个分支,特性优于MySQL
2、MariaDB 的查询效率高
3、MariaDB 支持的存储引擎比较多
4、数据的复制,MariaDB 支持数据的迁移,MySQL 不支持
数据库操作
1、首先需要登录到数据库,数据库的初始化以及建立连接
MYSQL* mysql = mysql_init(NULL);
mysql_real_connect();//连接
2、之后利用 sprintf 进行封装语句,然后执行mysql_query();
读取MySQL数据
获取命令结果函数 :mysql_store_result()
读取字段函数 :mysql_fetch_fields()
读取字段数量函数 :mysql_num_fields()
读取数据函数 :mysql_fetch_row()
释放结果函数 :mysql_free_result(result);
mysql_fetch_row返回的是一个char型的双指针,指向对应字段数量的数组。数组里面的数据数据以string的形式展现