(实训)C/S架构的考试系统(mysql + socket)
首先,要完成通信至少要建2个工程,分别为服务端与客户端,这两个工程的环境配置与头文件添加都要按以下步骤进行
一、环境配置
先说mysql环境配置。
右键项目名称,找到属性。
配置属性->调试->环境:将mysqlmysql server bin 的路径复制,写PATH=路径
其中,如果没有自己定义,那么mysql文件夹一般在C:program Fiels中。
而后,仍然在属性栏中的C/C++中选择常规,将mysql server 中的include文件夹的路径编辑进附加包含目录中去。别忘了加英文的分号:
接着选择链接器,如下图将lib文件夹的路径编辑进去:
接着选择链接器的输入,点击附加依赖项,选择右边的小箭头,编辑,然后输入: libmysql.lib,选择确定:
然后为代码添加头文件<mysql>。编译后如果报错,则进行以下操作:
进入mysql server的lib文件夹,复制libmysql.dll文件,而后打开项目文件夹,返回上一级。
将该文件复制进x64的debug文件夹内。
至此,配置结束,如果仍报错可以适当更改libmysql.dll的位置。
二、mysql笔记
这份笔记我是看黑马程序员的视频总结的。由于实训使用mysql的消息突然,我的mysql只学了2天,不过也算勉强会使用。而mysql与c++的联动则是花费了我很大很大功夫,查了巨量资料,问了很多人才勉强入门,了解到曾经未曾听闻也无从下手的函数。下面是我整理出的极其、极其干货的一分笔记,查询mysql语法以及mysql与c++联动的函数时很方便。我先放两张截图告诉大家重点:
1:mysql语句在哪查:
从“纯sql语句”向下便是mysql语句干货,查起来非常方便,向上则是mysql的基本数据类型。学习前大致看看,有印象即可。
2.c++中的mysql函数在哪查:
从此处向下便是。后面还有一些socket的语法,不过我没有细心总结 ,大家可以不看。
MYSQL注释: MySQL 单行注释 1) 单行注释可以使用#注释符,#注释符后直接加注释内容。格式如下: #注释内容 2) 单行注释可以使用--注释符,--注释符后需要加一个空格,注释才能生效。格式如下: -- 注释内容 #和--的区别就是:#后面直接加注释内容,而--的第 2 个破折号后需要跟一个空格符在加注释内容。 MySQL 多行注释 多行注释使用/* */注释符。/*用于注释内容的开头,*/用于注释内容的结尾。多行注释格式如下: /* 第一行注释内容 第二行注释内容 */ MYSQL数据类型: 整数类型 字节 有符号取值范围 无符号取值范围 TINYINT 1 -128~127 0~255 SMALLINT 2 -32768~32767 0~65535 MEDIUMINT 3 -8388608~8388607 0~16777215 INT 4 -2147483648~2147483647 0~4294967295 BIGINT 8 -9223372036854775808~9223372036854775807 0~18446744073709551615 整数类型的可选属性有三个: (M) 表示最低显示宽度,例如int(5),当数据宽度小于5位时在数字前面需要用字符填满宽度。该项功能要配合”ZEROFILL“使用,否则指定宽度无效。 如果设置了显示宽度,不会对插入的数据有影响,还是按照类型的实际宽度保存。从MySQL8.0.17开始,整数数据类型不推荐使用显示宽度属性。 UNSIGNED 表示无符号类型。使用:INT UNSIGNED ZEROFILL 表示0填充。如果某列是ZEROFILL,那么mysql会自动为当前列添加UNSIGNED属性。 如果指定了ZEROFILL表示不够M位时,用0在左边填充,超过M位时,只要不超过数据存储范围即可。 (M)必须和UNSIGNED ZEROFILL一起使用才有意义,M的值跟int所占多少存储空间没有关系,int(3),int(4)在磁盘上都是占用4个字节。 字符串类型 字节 描述及存储需求 CHAR(M) M M为0~255之间的整数 VARCHAR(M) M为0~65536之间的整数 TINYBLOB 允许长度0~255字节 BLOB 允许长度0~65535字节 MEDUIMBLOB 允许长度0~167772150字节 LONGBLOB 允许长度0~4294967295 TINYTEXT 允许长度0~255字节 TEXT 允许长度0~65535字节 MEDIUMTEXT 允许长度0~167772150字节 LONGTEXT 允许长度0~4294967295字节 VARBINARY(M) M 允许长度0~M个字节的边长字节字符集 BINARY(M) M 允许长度0~M个字节的定长字节字符集 CHAR与VARCHAR类型 CHAR和VARCHAR很类似,都是用来保存Mysql中较短的字符串,主要区别在于:CHAR列的长度固定为创建表时声明的长度,长度可以为从 0~255的任何值,而VARCHAR的值可以是变长字符串,长度可以指定0~65535之间的值,在检索的时候,CHAR列会删除尾部的空格而 VARCHAR则保留了这些空格。 ENUM类型 枚举类型,它的值范围需要在创建表时通过枚举方式显示指定,对1~255个成员的枚举需要1个字节存储,对于255~65535个成员,需要2 个字节存储,最多允许65535个成员。 SET类型 SET和enum非常相似,里面可以包含0~64个成员,根据成员的不同,存储上也有不同。 1~8成员的集合,占1个字节 9~16成员的集合,占2个字节 17~24成员的集合,占3个字节 25~32成员的集合,占4个字节 33~64成员的集合,占8个字节 set类型一次可以选取多个成员,而ENUM则只能选一个,就相当于ENUM是单选,而set是复选。 浮点类型 占用空间 精度 精确性 FLOAT 4 单精度 精确到小数点后7位小数 DOUBLE 8 双精度 精确到小数点后15位小数 DECIMAL 变长 高精度 精确到小数点后65位小数 数据精度说明 对于浮点数类型,在MySQL中单精度使用4个字节,双精度使用8个字节。 MySQL允许使用非标准语法(其他数据库未必支持,因此如果涉及到数据迁移,则最好不要这么用):FLOAT(M,D) , DOUBLE(M,D),M称为精 度(整数+小数),D称为标度(小数)。D<M<=255,0<=D<=30。例如:定义FLOAT(5,2)的一个列可以显示-999.99~999-99,超出这个范围 会报错。FLOAT和DOUBLE类型在不知道(M,D)时,默认按照实际的精度(由实际硬件和操作系统决定)来显示。不管是否显示设置了精度(M,D) ,MySQL的处理方案如下:如果存储时,整数部分超出范围,MySQL就会报错,不允许存这样的值。如果存储时,小数点部分超出范围,则:若四 舍五入后,整数部分没有超出范围,则只是警告,但能成功操作并且四舍五入删除多余的小数位后保存。例如FLOAT(5,2)插入999.009,近似 结果是999.01;若四舍五入后,整数部分超出范围,则报错; 定点类型 字节数 含义 DECIMAL(M,D),DEC,NUMERIC M+2字节 有效范围由M和D决定 使用 DECIMAL(M,D) 的方式表示高精度小数。其中,M被称为精度,D被称为标度。0<=M<=65,0<=D<=30,D<M。例如,定义DECIMAL(5,2) 的类型,表示该列取值范围是-999.99~999.99。DECIMAL(M,D)的最大取值范围与DOUBLE类型一样,但是有效的数据范围是由M和D决定的。 DECIMAL 的存储空间并不是固定的,由精度值M决定,总共占用的存储空间为M+2个字节。也就是说,在一些对精度要求不高的场景下,比起占用 同样字节长度的定点数,浮点数表达的数值范围可以更大一些。定点数在MySQL内部是以字符串的形式进行存储,这就决定了它一定是精准的。当 DECIMAL类型不指定精度和标度时,其默认为DECIMAL(10,0),表示有10个整数位,0个小数位,其范围:-9999999999~9999999999。当数 据的精度超出了定点数类型的精度范围时,则MySQL同样会进行四舍五入处理。 二进制字符串类型 长度 长度范围 占用空间 BIT(M) M 1<=M<=64 约为(M+7)/8字节 如果没有指定M,默认是1位。如果插入的是10进制的,会转为二进制插入。 在使用select命令查询字段时,可以使用bin()或hex()函数进行读取。 日期时间类型 名称 字节 日期格式 最小值 最大值 YEAR 年 1 YYYY或YY 1901 2155 TIME 时间 3 HH:MM:SS -838:59:59 838:59:59 DATE 日期 3 YYYY-MM-DD 1000-01-01 9999-12-03 DATETIME 日期时间 8 YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 9999-12-31 23:59:59 TIMESTAMP 日期时间 4 YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:00UTC 2038-01-19 03:14:07UTC 时间类型 TIME 的取值范围不是 -23:59:59~23:59:59 的原因是 MySQL 设计的 TIME 类型,不光表示一天之内的时间,而且可以 用来表示一个时间间隔,这个时间间隔可以超过 24 小时。 关于 ` ` 是 MySQL 的转义符,避免和 mysql 的本身的关键字冲突,只要你不在列名、表名中使用 mysql 的保留字或中文,就不需要转义。 所有的数据库都有类似的设置,不过mysql用的是`而已。通常用来说明其中的内容是数据库名、表名、字段名,不是关键字。例如: select from from table; 第一个from是字段名,最后的table表名,但是同时也是mysql关键字,这样执行的时候就会报错,所以应该使用 select `from` from `table`; 当然,为了便于阅读,不建议使用关键字作为字段名、表名,同时,应该对数据库名、表名、字段名用一对儿反引号包含。 []内表示可不写的内容,[]在编译时不用写 不区分大小写 纯SQL语句: DDL: 查询所有数据库: SHOW DATABASES; 查询当前数据库: SELECT DATABASE(); 创建数据库: CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则]; 删除数据库: DROP DATABASE [IF EXISTS] 数据库名; 使用数据库: USE 数据库名; 查询当前正在使用的数据库中的所有表: SHOW TABLES; 查询表结构: DESC 表名; 创建表: CREATE TABLE 表名( 字段1 字段1类型 [COMMENT 字段1注释], ... 字段n 字段n类型 [COMMENT 字段n注释]//最后一行无逗号 )[COMMENT 表注释]; 向表中添加字段(列): ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束]; 修改字段(列): 修改数据类型:ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度); 修改字段名和类型:ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束]; 删除字段:ALTER TABLE 表名 DROP 字段名; 修改表名:ALTER TABLE 表名 RENAME ID 新表名; 删除表:DROP TABLE [IF EXISTS] 表名; 删除并重新创建表:TRUNCATE TABLE 表名; DML: 给指定字段添加数据:INSERT INTO 表名(字段名1,字段名2...) VALUES (值1,值2...); 给全部字段添加数据:INSERT INTO 表名 VALUES(值1,值2...); 批量添加数据:INSERT INTO 表名(字段名1,字段名2...) VALUES (值1,值2...),(值1,值2...)...; INSERT INTO 表名 VALUES (值1,值2...),(值1,值2...)...; 修改数据:UPDATE 表名 SET 字段名1=值1,字段名2=值2,...[WHERE 条件]; 注意:如果没有条件,代表要修改该表选中字段名下的所有数据 删除数据:DELETE FROM 表名 [WHERE 条件]; * 字段列表 即:字段名1,字段名2... DQL: 查询多字段:SELECT 字段1,字段2... FROM 表名; 查询全部字段(不推荐这样写):SELECT * FROM 表名; 设置别名:SELECT 字段1 [AS 别名1],字段2 [AS 别名2]...FROM 表名; 去除重复记录:SELECT DISTINCT 字段列表 FROM 表名; 条件查询: SELECT 字段列表 FROM 表名 WHERE 条件列表; MYSQL条件类型: 比较运算符 逻辑运算符 模糊匹配 like 等于 = and 或 && %表示任意多个任意字符 大于 > or 或 || _表示一个任意字符 大于等于 >= not 或 ! 小于 < 小于等于 <= 不等于 != 或 <> 范围 BETWEEN...AND... 左小于右 列表多选一 IN(...) 范围查询 空值查询 in表示在一个非连续的范围内 is null not in表示不在一个非连续的范围内 is not null 查询没有学号的学生: SELECT * FROM 表名 WHERE 字段名 IS NULL; 查询长度为2的字符: select 字段列表 from 表名 where 字段名 like'__'; 查询名字以汽车车结尾的产品 select 字段列表 from 表名 where name like '%汽车'; 查询姓商的同学: select 字段列表 from 表名 where name like '商%'; 特殊的范围查询: select 字段列表 from 表名 where 字段名 between 值1 and 值2; 值1必须小于等于值2 select 字段列表 from 表名 where 字段名 in(值1,值2...); 多个条件之间用逻辑运算符链接 聚合函数: 常见聚合函数: count 统计数量 max 最大值 min 最小值 avg 平均值 sum 求和 求表中的数据数量:SELECT COUTN(*) FROM 表名; 求表中某字段的数据数量:SELECT COUNT(数据名) FROM 表名; 求表中某字段的平均值:SELECT AVG(字段名) FROM 表名; 求表中某字段的最大值:SELECT MAX(字段名) FROM 表名; 求所有名字叫'阿白'的学生的最小身高:SELECT MIN(height) FROM student where name = '阿白'; 分组查询: SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件]; 注意:where 与 having 的区别 where 分组前过滤,不满足where条件的不参与分组 having 分组后过滤,对分组结果进行过滤 查询男女人数:select gender, count(*) from emp grop by gender; 显示如下: gender `count(*)` 女 女生人数 男 男生人数 查询年龄<45岁的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址 select workaddress as 工作地址, count(*) as 人数 from employee where age < 45 group by 工作地址 having 人数 >= 3; 执行顺序:where > 聚合函数 > having 排序查询: SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2...; 排序方式: 升序(默认值):ASC 降序:DESC 根据年龄对公司的员工升序排序: SELECT * FROM employee order by age; 根据入职时间降序排序: select * from employee order by entryDate desc; 先按年龄升序排序,年龄相同按照入职时间降序排序: select * from employee order by age, entryDate desc; 分页查询: select 字段列表 from 表名 limit 起始索引,查询记录数; 起始索引从0开始,起始索引 = (查询页码 - 1) * 每页显示的记录数 如果查询的是第一页的数据,起始索引可省略 例: 查询第一页员工数据,每页显示10条记录: select * from empployee limit 0,10; 查询第二页员工数据,每页显示10条记录: select * from empployee limit 10,10; 查询第三页前八条员工记录,每页显示10条数据 select * from employee limit 20,8; DQL编写顺序: select 字段列表 from 表名 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数 DQL执行顺序: from->where->group by->having->select->order by->limit 别名的特殊使用: select e.name , e.age from employee e where e.age > 15; DCL: 查询用户: USE mysql; select * from user; 创建用户: CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码'; 修改用户密码: ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码'; 删除用户 DROP USER '用户名'@'主机名'; 例: 创建用户 ab, 只能在当前主机(localhost)访问,密码为aaa; create user 'ab'@'localhost' identified by 'aaa'; 创建用户 cd, 可以在任意主机访问,密码为bbb; create user 'cd'@'%', identified by 'bbb'; 修改 ab 的密码为'ccc'; alter user 'ab'@'localhost' idetified with mysql_native_password by 'ccc'; 加密方式↑ 权限控制: 查询权限:SHOW GRANTS FOR '用户名'@'主机名'; 授予权限:GRANT 权限列表 ON 数据库名,表名 TO '用户名'@'主机名'; 撤销权限:REVOKE 权限列表 ON 数据库名,表名 FROM '用户名'@'主机名'; 例: grant all on employee.* to 'cd'@'%'; revoke all on employee.* from 'cd'@'%'; grant all *.* to 'ab'@'localhost'; 函数 字符串函数: concat(s1,s2...sn) 将字符串s1~sn拼接为一个字符串 lower(str) 转小写 upper(str) 转大写 lpad(str,n,pad) 左填充,用字符串pad填充str到长度n rpad(str,n,pad) 右填充,用字符串pad填充str到长度n trim(str) 去掉字符串头部和尾部的空格 substring(str,start,len) 返回str从start起长度len的字符串,索引从1开始 例: select concat('hello', 'mysql'); select lower('HEllo'); select lpad('01',5,'-'); select rpad('01',6,'a3b'); update employee set worknumber = lpad(worknumber,5,'0'); ... 数值函数: celi(x) 对x向上取整 floor(x) 对x向下取整 mod(x,y) 返回 x%y rand() 返回0~1内的随机数 round(x,y) 求参数x的四舍五入的值,保留y位小数 例: 生成六位验证码 select lpad(round(rand()*1000000, 0), 6, '0'); 日期函数: curdate() 返回当前日期 curtime() 返回当前时间 now() 返回当前日期和时间 year(date) 获取指定date的年份 month(date) 获取指定date的月份 day(date) 获取指定date的日期 date_add(date, interval expr type) 返回一个日期/时间值加上一个时间间隔expr后的时间值 datediff(date1,date2) 返回起止时间之间的天数 例: select date_add(now(), interval 70 month); select datediff('2021-10-01','2022-12-15'); ...(可嵌套) 流程控制函数: if(value, t, f) 如果value为true,返回t,否则返回f ifnull(value1, value2) 如果value1不为空,返回value1,否则返回value2 case when [val1] then [res1] ... else [default] end 如果val1为true,返回res1,...否则返回default默认值 case [expr] when [val1] then [res1]...else [default] end; 如果expr的值等于val1,返回res1,...否则返回default默认值 例: select ifnull('', 'default'); 返回'' select ifnull(null, 'default'); 返回default select id, name, (case when math >= 85 then '优秀' when math >= 60 then '及格' else '不及格' end) '数学'; from score; select name, (case workaddress when '北京' then '一线' when '上海' then '一线' else '二线' end) as '工作地址' from employee; 约束 关键字 约束名 效果 not null 非空约束 限制该字段数据不能为null unique 唯一约束 保证该字段所有数据都唯一,不重复 primary key 主键约束 主键是一行数据的唯一标识,非空且唯一 default 默认约束 保存数据时,如果未指定该字段的值,则采用默认值 check 检查约束 保证字段值满足某一个条件 foreign key 外键约束 用来让两张表的数据之间建立连接,保证数据的一致性和完整性 外键行为 说明 no action 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新 restrict 与no action一致 cascade 当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则也删除/更新外键在字表中的记录 set null 当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键的值为null(要求外键允许取null) set default 父表有变更时,子表将外键列设置为一个默认的值 添加外键: 创建表时: create table 表名( 字段名 数据类型... ... [constraint][外键名称] foreign key (外键字段名) references 主表(主表列名) )...; 创建表后: alter table 表名 add constraint 外键名称 foreign key (外键字段名) references 主表(主表列名); 删除外键: alter table 表名 drop foreign key 外键名称; 设置外键行为: 添加外键的语法 on update 更新时的行为 on delete 删除时的行为 例: create table user( 自动增长↓ id int primary key auto_increment comment '主键', name varchar(10) not null unique comment '姓名', age int check ( age > 0 && age < 120 ) comment '年龄', status char(1) default '1' comment '状态', gender char(1) comment '性别' dept_id int comment '外键约束' #之后用来链接外键 )comment '用户表'; alter table employee add constraint fk_emp_dept_id foreign key (dept_id) references dept(id); alter table employee drop foreign key fk_emp_dept_id; 多表查询 查看多表关系:在DG中,右键中间表,最下面选择以可视化界面展示 一对多:多的一方的外键链接一的一方的主键 多对多:建立中间表并建立两个外键,分别链接另外两表的主键 一对一(多用于拆分的表):任意一方加入外键,关联另外一方的主键,并设置外键为唯一(unique) 有效查询多个有关的表: select * from emp, dept where emp.dept_id = dept.id; 内连接:查询A,B交集的数据 隐式内连接:select 字段列表 from 表1,表2 where 条件... 显式内连接:select 字段列表 from 表1[inner] join 表2 on 连接条件... c++中的MYSQL 所需头文件 #include <WinSock2.h> #include <mysql.h> #pragma comment(lib,"libmysql.lib") #pragma comment(lib,"wsock32.lib") #pragma comment(lib, "ws2_32.lib") 一般将执行语句封入string,再通过.c_str()传入相应函数 MYSQL* mysql = NULL 创建数据库对象 mysql_init() 初始化数据库 mysql_options() 连接设置 mysql_real_connect() 连接数据库 mysql_query() 传入指令 mysql_store_result() 获得数据库结果集 mysql_num_rows() 获得结果集中的行数 mysql_num_fields() 获得结果集中的列数 mysql_fetch_field() 获取列的字段名、字段类型和大小等信息 mysql_fetch_row() 检索结果集的下一行 mysql_free_result() 释放先前查询所储存的数据集 mysql_close() 关闭当前数据库链接 errorIntoMySQL() 弹出错误 mysql_store_result()与 mysql_use_result(): mysql_store_result()立即检索所有的行,而 mysql_use_result()启动查询,但实际上并未获取任何行, mysql_store_result()假设随后会调用 mysql_fetch_row()检索记录。这些行检索的不同方法引起两者在其 他方面的不同。本节加以比较,以便了解如何选择最适合应用程序的方法。当mysql_store_result()从服务器 上检索结果集时,就提取了行,并为之分配内存,存储到客户机中,随后调用 mysql_fetch_row()就再也不会返 回错误,因为它仅仅是把行脱离了已经保留结果集的数据结构。mysql_fetch_row()返回 NULL始终表示已经到达 结果集的末端。相反,mysql_use_result()本身不检索任何行,而只是启动一个逐行的检索,就是说必须对每行 调用 mysql_fetch_row()来自己完成。既然如此,虽然正常情况下,mysql_fetch_row()返回NULL仍然表示此 时已到达结果集的末端,但也可能表示在与服务器通信时发生错误。可通过调用mysql_errno()和mysql_error() 将两者区分开来。与mysql_use_result()相比,mysql_store_result()有着较高的内存和处理需求,因为是 在客户机上维护整个结果集,所以内存分配和创建数据结构的耗费是非常巨大的,要冒着溢出内存的危险来检索大型 结果集,如果想一次检索多个行,可用 mysql_use_result()。mysql_use_result()有着较低的内存需求,因为 只需给每次处理的单行分配足够的空间。这样速度就较快,因为不必为结果集建立复杂的数据结构。另一方面, mysql_use_result()把较大的负载加到了服务器上,它必须保留结果集中的行,直到客户机看起来适合检索所有的 行。这就使某些类型的客户机程序不适用mysql_use_result(): c++中的TCP WSAData wsaData: 存放windows socket初始化信息 WSAStartup: 使库文件与当前的应用程序绑定,以调用该版本的socket的各种函数 原型:int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData ); 参数:wVersionRequested是Windows Sockets API提供的调用方可使用的最高版本号。高位字节指出 副版本(修正)号,低位字节指明主版本号。lpWSAData 是指向WSADATA数据结构的指针,用来接收 Windows Sockets实现的细节。 返回值:返回0则执行成功。 word类型:储存socket编程中的版本信息 makeword():创建word类型。 LOBYTE(): 取 16 进制数的最低字节 HIBYTE(): 取 16 进制数的最高字节 //这俩的返回值不用管,照着写就行,没查到,老师说是默认( WSACleanup(): 清理,成功返回0,可用WSAGetLastError来获取错误码。 注意: 当调用了WSACleanup,在此进程中任何挂起的或者异步的套接字调用都会取消,而且不会发出通知消息也不会设置事件对象。 为了使挂起的数据发送出去,应用程序应该使用shutdown来关闭连接,然后一直等待关闭完成再调用closesocket和WSACleanup。 和WSAStartup一样,WSACleanup也不能在DllMain中调用(可能会死锁)。 SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0): 建立一个协议族为AF_INET、协议类型SOCK_STREAM、协议编号为0的套接字 AF_UNIX(本机通信) AF_INET(TCP/IP – IPv4) AF_INET6(TCP/IP – IPv6) SOCK_STREAM(TCP流) SOCK_DGRAM(UDP数据报) SOCK_RAW(原始套接字) INVALID_SOCKET: 表示该 socket fd 无效。(判断正误) sockaddr_in:internet环境下套接字的地址形式 htonl:把本机字节顺序转化为网络字节顺序 h:host 本地主机 to:to n:net 网络的意思 l:unsigned long INADDR_ANY:监听0.0.0.0地址 bind():给socket绑定端口号与具体位置 参数 1:需要绑定的socket。 参数 2:存放了服务端用于通信的地址和端口。 参数3:表示 addr 结构体的大小 返回值:成功则返回0 ,失败返回-1,错误原因存于 errno 中。如果绑定的 地址错误,或者端口已被占用,bind 函数一定会报错,否则一般不会返回错误。 sockaddr:一种通用的套接字地址 CONNECT_NUM_MAX:(没搜到这个宏) sockaddr_in:internet环境下套接字的地址形式 accept():接收一个套接字中已建立的连接 参数1:利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址(一般为服务器的套接字),并且通过listen()一直在监听连接; 参数2:指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写,返回地址addr的确切格式由套接字的地址 类别(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,应该置为NULL; 参数3:一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,函数返回时包含对等地址(一般为服务器地址)的实际数值; recv(): 从连接的套接字或绑定的无连接套接字接收数据 参数1:指定接收端套接字描述符; 参数2:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据; 参数3:指明buf的长度; 参数4:一般置0。 返回值:<0 出错; =0 连接关闭; >0 接收到数据大小 send():将我们的数据复制黏贴进系统的协议发送缓冲区,计算机伺机发送出去 参数1:标识已连接套接字的描述符。 参数2:指向包含要传输的数据的缓冲区的指针。 参数3:buf参数指向的缓冲区中数据的长度(以字节为单位)。 参数4:一组标志,指定进行呼叫的方式。 通过将按位或运算符与以下任何值一起使用来构造此参数。 返回值:成功返回写入的字节数;执行失败,返回SOCKET_ERROR closesocket():关闭一个套接口
三、头文件添加
下面是代码。代码分为三部分 服务端,客户端,还有一个我自己定义的stdafx头文件。这个头文件是vs库自带的。我的出于某些原因没有。当然,如果你有的话,将stdafx头文件放在最上方,下方添加以下头文件:
#include <WinSock2.h> #include <Ws2tcpip.h> #include <mysql.h> #pragma comment(lib,"libmysql.lib") #pragma comment(lib,"wsock32.lib") #pragma comment(lib,"ws2_32.lib") #include <iostream> #include<algorithm> #include<vector> #include<string> #include <unordered_set> #include <ctime> #include <random> #include <sstream> #include<Windows.h>
如果不知道头文件如何创建:
刚创好的头文件会自带一行#pragma once。自定义中写过了,覆盖即可。
自定义的stdafx头文件内容:
// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #if !defined(AFX_STDAFX_H__4607A810_33E2_483D_80D8_BE41F0D473D5__INCLUDED_) #define AFX_STDAFX_H__4607A810_33E2_483D_80D8_BE41F0D473D5__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // Insert your headers here #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #define DLLEXPORT __declspec(dllexport) #define DLLIMPORT __declspec(dllimport) #include <WinSock2.h> #include <Ws2tcpip.h> #include <mysql.h> #pragma comment(lib,"libmysql.lib") #pragma comment(lib,"wsock32.lib") #pragma comment(lib,"ws2_32.lib") #include <iostream> #include<algorithm> #include<vector> #include<string> #include <unordered_set> #include <ctime> #include <random> #include <sstream> #include<Windows.h> // TODO: reference additional headers your program requires here void Msg(char* szFormat, ...); void dbMsg(char* szFormat, ...); //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_STDAFX_H__4607A810_33E2_483D_80D8_BE41F0D473D5__INCLUDED_)
需要注意的是,这个头文件服务端,客户端两个工程都需要添加
四、服务端与客户端的创建
先说明很重要的一点。安装好后每个人都设置了自己的mysql账号和密码。在我的代码中我会将他们删去,如果想使用这份代码,那么需要添上自己的。代码具体位置在服务端的1467行左右:
涂黑的,左边是账号,右边是密码。
1.服务端的创建:
别忘了自定义头文件stdafx或者按照上面已有stdafx的情况添加我列出的头文件
代码:
#include "stdafx.h" WSADATA localWsaData; SOCKET connectSocket; SOCKET serverSocket; HANDLE hMUTEX; int sendInf(std::string sendBuff) { sendBuff += ''; if (sendBuff == "#") { sendBuff = "system: 服务器端请求终止对话...n"; closesocket(serverSocket); WSACleanup(); return 0; } if (send(connectSocket, sendBuff.c_str(), sizeof(char) * sendBuff.size(), 0) == SOCKET_ERROR) { std::cout << "system: 发送连接消息失败: " << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); return -1; } return 1; } std::string receiveInf() { char recvBuff[1024]{}; if (recv(connectSocket, recvBuff, 1024, 0) == SOCKET_ERROR) { std::cout << "system: 接收连接消息失败: " << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); return ""; } return recvBuff; } //便捷读取 class SafeRead { public: //录入数字 static std::string readNum(int length, const std::string& oldNum) { std::string inf; //label位置 label:while (true) { std::cout << " 请输入数字:"; getline(std::cin, inf); if (inf == "n" || inf.empty()) { return oldNum; } else if ((int)inf.length() > length) { std::cout << "nt长度超过" << length << "位(计算需要包含小数点),请重新输入。n"; continue; } std::stringstream sin(inf); double d; char c; bool flag = true; if (!(sin >> d)) flag = false; if (sin >> c) flag = false; if (!flag) { std::cout << "输入的不是一个数字,请重新输入" << std::endl; continue; } break; } //删除前导零 std::string::iterator it = inf.begin(); for (unsigned int i = 0; i < inf.length() - 1; i++) {//单0不删,一串0只留一个 if (inf[i] == '-') continue; if (inf[i] != '0') break; if (inf[i] == '0' && inf[i + 1] == '.') break; inf.erase(it); it++; } return inf; } //录入有限制的字符串,用于读取基本信息 static std::string readString(int length, std::string old) { std::string inf; while (true) { getline(std::cin, inf); if (inf == "n" || inf.empty()) { return old; } else if ((int)inf.length() > length) { std::cout << "nt信息长度超过" << length << ",请重新输入。n"; continue; } return inf; } } //读取文本块,以~~~结束 static std::string readText(int length, std::string old) { while (true) { std::string ans; while (true) { std::string inf; getline(std::cin, inf); if (inf == "~~~") { break; } else { ans = ans + inf + "n"; } } if (ans.size() > length) { std::cout << "当前文本长度(包括空格)为 " << ans.size() << ",已超过限定长度 " << length << ",请重新输入..." << std::endl; continue; } return ans; } } }; //double转string函数 std::string lfToStr(double num) { std::stringstream ss; std::string str; ss << num; ss >> str; return str; } //string转换为double函数 double strToLf(const std::string& number) { double lf = 0, lfi = 0, x = 10; int i = 0, f = 1, times = 1, length = (int)number.length(); while (number[i] < '0' || number[i] > '9') {//跳过可能存在的¥,$ 或 - i++; if (number[i] == '-') f *= -1; } //整数位 while (i < length) { if (number[i] == '.') { break; } lf = lf * 10 + number[i] - '0'; i++; } //小数位,++i跳过‘ . ’ while (++i < length) { lfi += (number[i] - '0') / x; x *= 10; } return times * f * (lf + lfi); } //创建不重复的随机数组 std::vector<int> createRandList(int left, int right) { int length = right - left + 1; std::default_random_engine start; std::uniform_int_distribution<int> getRand(left, right); start.seed(time(0)); std::unordered_set<int> list; while (list.size() < length) { list.insert(getRand(start)); } std::vector<int> randomSunject(list.begin(), list.end()); return randomSunject; } MYSQL localMysql; //mysql c++的使用 class MysqlOperation { public: //封装query函数 static bool useQuery(MYSQL* mysql, std::string instruction) { int res = mysql_query(mysql, instruction.c_str()); if (res) { std::cout << mysql_error(mysql) << std::endl; return false; } else { return true; } } //基础的搜索框架,返回处理过的string型结果集 static std::string basicSelect(MYSQL* mysql) { MYSQL_RES* result = mysql_store_result(mysql); int column = mysql_num_fields(result); std::string ans; MYSQL_ROW row = mysql_fetch_row(result); while (row) { for (int i = 0; i < column; i++) { if (row[i]) { ans += row[i]; } else { ans += "null"; } if (i < column - 1) { ans += "t"; } } row = mysql_fetch_row(result); if (row) { ans += "n"; } } mysql_free_result(result); return ans; } //连接数据库 static bool ConnectDB(std::string host, std::string user, std::string password, std::string DBname, int port) { MYSQL* mysql = mysql_init(&localMysql);//初始化localMysql if (!mysql) { std::cout << mysql_error(mysql) << std::endl; return false; } mysql_options(&localMysql, MYSQL_SET_CHARSET_NAME, "GBK"); mysql = mysql_real_connect(&localMysql, host.c_str(), user.c_str(), password.c_str(), DBname.c_str(), port, NULL, 0); if (mysql == nullptr) { std::cout << mysql_error(mysql) << std::endl; return false; } std::cout << "连接mysql成功!n";//连接成功反馈 std::string DBName = "ExaminationSystem"; createDatabase(DBName); bool res = useQuery(&localMysql, "use ExaminationSystem"); if (res) { std::cout << "已转到数据库"ExaminationSystem"" << std::endl; } return res; } //创建数据库 static bool createDatabase(std::string& DBName) { std::string oper = "create database if not exists " + DBName; bool res = useQuery(&localMysql, oper); if (res) { std::cout << """ << DBName << ""数据库创建成功或已存在" << std::endl; } return res; } //更改使用的数据库 static bool changeUsingBase(std::string DBName) { std::string oper = "use " + DBName; bool res = useQuery(&localMysql, oper); if (res) { std::cout << "数据库使用情况已更改,当前使用的数据库为:"" + DBName + """ << std::endl; } return res; } //查看连接状态 static bool checkIfConnectDB() { MYSQL* mysql = &localMysql; int res = mysql_query(mysql, "select database()"); if (res) { std::cout << mysql_error(mysql) << std::endl; return false; } MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW line = mysql_fetch_row(result); if (!line) { std::cout << "未连接任何数据库" << std::endl; return false; } else { std::cout << "数据库连接状态:已连接n" << "连接的数据库为:" << line[0] << std::endl; return true; } } //删除数据库 static bool deleteDataBase(std::string DBName) { for (auto iter = DBName.begin(); iter != DBName.end(); iter++) {//去除空格 if (isblank(*iter) != 0) { DBName.erase(iter--); } } std::transform(DBName.begin(), DBName.end(), DBName.begin(), ::tolower);//转小写 if (DBName == "mysql" || DBName == "sys" || DBName == "information_schema" || DBName == "performance_schema" || DBName == "serverobjects") { std::cout << "该库不可删除!!"; } mysql_close(&localMysql); mysql_init(&localMysql); std::string oper = "drop database " + DBName; bool res = useQuery(&localMysql, oper); return res; } //查看所有表 static bool checkAllTable(std::string DBName) { bool res = useQuery(&localMysql, "show tables"); return res; } //创建表 static bool createTable(std::string tableName, std::string basicField, std::string fieldType, std::string key, std::string autoIncrement, std::string fieldComment, std::string tableComment = "") { std::string oper = "create table if not exists `" + tableName + "` (`" + basicField + "` " + fieldType + " " + key + " " + autoIncrement + " comment '" + fieldComment + "')comment'" + tableComment + "'"; bool res = useQuery(&localMysql, oper.c_str()); return res; } //修改表名 static bool changeTableName(std::string tableName, std::string newTableName) { std::string oper = "alter table `" + tableName + "` rename id `" + newTableName + "`"; bool res = useQuery(&localMysql, oper.c_str()); return res; } //删除表 static bool deleteTable(std::string tableName) { MYSQL* mysql = &localMysql; std::string oper = "drop table if exists`" + tableName + "`"; bool res = useQuery(mysql, oper.c_str()); return res; } //查看表结构: static bool checkTableStructure(std::string tableName) { MYSQL* mysql = &localMysql; std::string oper = "desc `" + tableName + "`"; bool res = useQuery(mysql, oper.c_str()); if (res) { MYSQL_RES* result = mysql_store_result(mysql); int row = mysql_num_rows(result); int column = mysql_num_fields(result); MYSQL_ROW line = mysql_fetch_row(result); std::string answer = "FieldtTypetNulltKeytDefaulttExtran"; while (line) { for (int i = 0; i < column; i++) { if (i) { answer += "t"; } if (line[i]) { answer += line[i]; } else { answer += "null"; } } answer += "n"; line = mysql_fetch_row(result); } std::cout << answer << std::endl; mysql_free_result(result); } return true; } //添加字段 static bool addField(std::string tableName, std::string fieldName, std::string fieldType, std::string key, std::string autoIncrement, std::string fieldComment) { MYSQL* mysql = &localMysql; std::string oper = "alter table `" + tableName + "` add `" + fieldName + "` " + fieldType + " " + key + " " + autoIncrement + " comment '" + fieldComment + "' "; bool res = useQuery(mysql, oper.c_str()); return res; } //修改字段数据类型 static bool modifyFieldDataType(std::string tableName, std::string fieldName, std::string newDataType) { MYSQL* mysql = &localMysql; std::string oper = "alter table `" + tableName + "` modify `" + fieldName + "` " + newDataType; bool res = useQuery(mysql, oper.c_str()); return res; } //修改字段名和类型 static bool changeFieldNameDataType(std::string tableName, std::string fieldName, std::string newFieldName, std::string newDataType) { MYSQL* mysql = &localMysql; std::string oper = "alter table `" + tableName + "`change `" + fieldName + "` `" + newFieldName + "` " + newDataType; bool res = useQuery(mysql, oper.c_str()); return res; } //删除字段 static bool deleteField(std::string tableName, std::string fieldName) { MYSQL* mysql = &localMysql; std::string oper = "alter table `" + tableName + "` drop `" + fieldName + "`"; bool res = useQuery(mysql, oper.c_str()); return res; } //添加数据 static bool addData(std::string tableName, std::vector<std::string>fieldList, std::vector<std::vector<std::string>> dataList) { std::string oper = "insert into `" + tableName + "`"; std::string FL, DL; if (!fieldList.empty()) {//收集字段名 FL = " ( "; for (int i = 0; i < fieldList.size(); i++) { FL = FL + "`" + fieldList[i] + "`"; if (i < fieldList.size() - 1) { FL += ", "; } } FL += " ) "; } if (!dataList.empty()) {//收集要添加的数据 DL = " values "; for (int i = 0; i < dataList.size(); i++) { if (!dataList[i].empty()) { DL += " ( "; for (int j = 0; j < dataList[i].size(); j++) { DL = DL + "'" + dataList[i][j] + "'"; if (j < dataList[i].size() - 1) { DL += ", "; } } DL += " ) "; } if (i < dataList.size() - 1) { DL += ", "; } } } oper = oper + FL + DL; bool res = useQuery(&localMysql, oper.c_str()); return res; } //修改数据 static bool modifyData(std::string tableName, std::vector<std::string>fieldList, std::vector<std::string>dataList, std::string condition) { if (fieldList.size() != dataList.size()) { std::cout << "字段个数数与相对应的值的个数不符! 字段有 " << fieldList.size() << " 个, 值有 " << dataList.size() << " 个。" << std::endl; return false; } std::string oper = "update `" + tableName + "` set "; for (int i = 0; i < fieldList.size(); i++) { std::string tmp; tmp = "`" + fieldList[i] + "` = " + dataList[i]; if (i < fieldList.size() - 1) { tmp += ", "; } oper += tmp; } if (condition != "") { oper = oper + " where " + condition; } bool res = useQuery(&localMysql, oper); return res; } //删除数据 static bool deleteData(std::string tableName, std::string condition) { std::string oper = "delete from `" + tableName + "` "; if (condition != "") { oper = oper + "where " + condition; } bool res = useQuery(&localMysql, oper); return res; } //搜索函数及其重载 static bool selectTable(std::vector<std::string> fieldList, std::string tableName, std::string condition, std::vector<std::pair<std::string, std::string>> sortList) { MYSQL* mysql = &localMysql; std::string oper = "select "; for (int i = 0; i < fieldList.size(); i++) { oper = oper + "`" + fieldList[i] + "`"; if (i < fieldList.size() - 1) { oper += ", "; } } oper = oper + " from `" + tableName + "`"; if (!condition.empty()) { oper += condition; } if (!sortList.empty()) { oper += " order by "; for (int i = 0; i < sortList.size(); i++) { oper = oper + "`" + sortList[i].first + "` " + sortList[i].second; if (i < sortList.size() - 1) { oper += ", "; } } } bool res = useQuery(mysql, oper); if (res) { std::string ans; for (int i = 0; i < fieldList.size(); i++) { ans += fieldList[i]; if (i < fieldList.size() - 1) { ans += "t"; } } ans = ans + "n" + basicSelect(mysql); std::cout << ans << std::endl; } } static bool selectTable(std::vector<std::string> fieldList, std::string tableName, std::string condition, std::string gropField, std::string gropCondition, std::vector<std::pair<std::string, std::string>> sortList, std::pair<std::string, std::string> paging) { MYSQL* mysql = &localMysql; std::string oper = "select "; for (int i = 0; i < fieldList.size(); i++) { oper = oper + "`" + fieldList[i] + "`"; if (i < fieldList.size() - 1) { oper += ", "; } } oper = oper + " from `" + tableName + "`"; if (!condition.empty()) { oper += condition; } if (!gropField.empty()) { oper = oper + " group by " + gropField; if (!gropCondition.empty()) { oper = oper + " having " + gropCondition; } } if (!sortList.empty()) { oper += " order by "; for (int i = 0; i < sortList.size(); i++) { oper = oper + "`" + sortList[i].first + "` " + sortList[i].second; if (i < sortList.size() - 1) { oper += ", "; } } } if (!(paging.first == "0" && paging.second == "0")) { oper = oper + " limit " + paging.first + ", " + paging.second; } bool res = useQuery(mysql, oper); if (res) { std::string ans; for (int i = 0; i < fieldList.size(); i++) { ans += fieldList[i]; if (i < fieldList.size() - 1) { ans += "t"; } } ans = ans + "n" + basicSelect(mysql); std::cout << ans << std::endl; } } //添加外键 功能不必要,暂时停止开发 /*static bool addForeignKey(std::string foreignTable, std::string foreighName, std::string foreighFieldName, std::string mainTable, std::string mainFieldName) { MYSQL* mysql = &localMysql; std::string oper = "alter table `" + foreignTable + "` add constraint `" + foreighName + "` foreign key " + "" }*/ }; class Test { public: //设置考试 static void setTest() { std::vector<std::string>dataList; sendInf("请输入考试科目: "); dataList.push_back(receiveInf());//string 50 sendInf("请输入考试分值: "); dataList.push_back(receiveInf());//int 5 sendInf("请输入考试时间表,可换行。结束时另起一行输入 ~~~ 结束:n"); dataList.push_back(receiveInf());//text 500 bool res = MysqlOperation::addData("subject", std::vector<std::string>{"subName", "fullScore", "time"}, std::vector<std::vector<std::string>>{dataList}); if (res) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (res) { MysqlOperation::createTable(dataList[0], "id", "int", "", "", "", ""); MysqlOperation::addField(dataList[0], "studentName", "varchar(20)", "", "", ""); MysqlOperation::addField(dataList[0], "studentMajor", "varchar(20)", "", "", ""); MysqlOperation::addField(dataList[0], "studentGrade", "int", "", "", ""); MysqlOperation::addField(dataList[0], "studentClass", "int", "", "", ""); MysqlOperation::addField(dataList[0], "studentAccont", "varchar(20)", "", "", ""); MysqlOperation::addField(dataList[0], "score", "double", "", "", ""); sendInf("设置成功!"); receiveInf();//保证程序正常运行 } } //创建试卷 static void createTest() { MYSQL* mysql = &localMysql; sendInf("请输入考试科目:"); std::string testName = receiveInf();//string 50 std::string oper = "select subName from `subject` where subName = '" + testName + "'"; bool res = MysqlOperation::useQuery(mysql, oper); std::string test; if (res) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (res) { test = MysqlOperation::basicSelect(mysql); bool ress = test.empty(); if (ress) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (ress) { sendInf("未找到该科目的考试信息,是否先设置考试? 1:现在设置 2: 暂时不用n请输入选择:"); std::string low = receiveInf();//num 1 de 2 if (low == "1") { setTest(); } else { return; } } else { bool res1 = MysqlOperation::createTable(testName + "test", "id", "int", "primary key", "auto_increment", "序号"); bool res2 = MysqlOperation::addField(testName + "test", "type", "varchar(20)", "", "", "题目类型"); bool res3 = MysqlOperation::addField(testName + "test", "topic", "varchar(1024)", "", "", "题目内容"); bool res4 = MysqlOperation::addField(testName + "test", "score", "double", "", "", "分值"); bool res5 = MysqlOperation::addField(testName + "test", "answer", "varchar(1024)", "", "", "答案"); addSubject(testName + "test"); } } } //添加试题 static void addSubject(std::string test) { sendInf("请开始添加题目:n"); receiveInf();//保证程序正常运行 std::vector<std::vector<std::string>> testList; while (true) { std::vector<std::string> testEdit; sendInf("请选择题目类型,输入4退出添加题目: 1 选择题 2 填空题 3 大题: "); std::string type = receiveInf();//num 1 de 0 if (type == "4") { break; } if (type != "1" && type != "2" && type != "3") { sendInf("暂不支持其他选项!n"); receiveInf();//保证程序正常运行 continue; } testEdit.push_back(type); std::string inf; sendInf("请输入题目内容,可换行。结束时另起一行输入 ~~~ 结束:n"); testEdit.push_back(receiveInf());//text 1024 de 未输入 while (true) { sendInf("请输入分值: "); inf = receiveInf();//num 4 de -1 if (inf.c_str()[0] == '-' || inf == "0") { sendInf("题目分值必须大于0,请重新设置!n"); receiveInf(); continue; } break; } testEdit.push_back(inf); if (type == "1") { sendInf("请输入答案选项: "); inf = receiveInf();//string 10 de 0 std::transform(inf.begin(), inf.end(), inf.begin(), ::toupper); testEdit.push_back(inf); } else { sendInf("请输入答案内容,可换行。结束时另起一行输入 ~~~ 结束:n"); testEdit.push_back(receiveInf());//text 1024 未输入 } testList.push_back(testEdit); sendInf("n"); receiveInf();//保证程序正常运行 } std::vector<std::string> fieldList = { "type", "topic", "score", "answer" }; MysqlOperation::addData(test, fieldList, testList); } //修改试题 static void modifySubject() { MYSQL* mysql = &localMysql; sendInf("请输入要修改删除试题的考试名称: "); std::string subName = receiveInf(); MysqlOperation::useQuery(mysql, "show tables"); MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row; bool flags = false; while (row = mysql_fetch_row(result)) { if (row[0] == subName) { flags = true; break; } } mysql_free_result(result); if (!flags) { sendInf("false"); } else { sendInf("true"); } receiveInf();//保证程序正常运行 if (!flags) { sendInf("没有该科目试卷"); receiveInf();//保证程序正常运行 } else { sendInf("当前试卷如下n"); receiveInf();//保证程序正常运行 MysqlOperation::useQuery(mysql, "select * from `" + subName + "test`"); result = mysql_store_result(mysql); int rnum = mysql_num_fields(result); std::string ans; while (row = mysql_fetch_row(result)) { for (int i = 0; i < rnum; i++) { if (i == 0) ans += "序号:"; if (i == 1) { std::string ri = row[i]; if (ri == "1") { ans += "类型:选择 代号:"; } else if (ri == "2") { ans += "类型:填空 代号:"; } else if (ri == "3") { ans += "类型:大题 代号:"; } } else if (i == 2) ans += "题目:n"; else if (i == 3) ans += "分值:"; else if (i == 4) ans += "答案:"; ans += row[i]; ans += "n"; } ans += "n"; } sendInf(ans);//送出试卷 receiveInf();//保证程序正常运行 sendInf("请选择要修改的题目编号"); std::string number = receiveInf();//保证程序正常运行 sendInf("请重新输入题目:"); receiveInf();//保证程序正常运行 std::vector<std::string> testEdit; while (true) { sendInf("请选择题目类型: 1 选择题 2 填空题 3 大题: "); std::string type = receiveInf();//num 1 de 0 if (type != "1" && type != "2" && type != "3") { sendInf("暂不支持其他选项!n"); receiveInf();//保证程序正常运行 continue; } testEdit.push_back(type); std::string inf; sendInf("请输入题目内容,可换行。结束时另起一行输入 ~~~ 结束:n"); testEdit.push_back(receiveInf());//text 1024 de 未输入 while (true) { sendInf("请输入分值: "); inf = receiveInf();//num 4 de -1 if (inf.c_str()[0] == '-' || inf == "0") { sendInf("题目分值必须大于0,请重新设置!n"); receiveInf(); continue; } break; } testEdit.push_back(inf); if (type == "1") { sendInf("请输入答案选项: "); inf = receiveInf();//string 1 de 0 std::transform(inf.begin(), inf.end(), inf.begin(), ::toupper); testEdit.push_back(inf); } else { sendInf("请输入答案内容,可换行。结束时另起一行输入 ~~~ 结束:n"); testEdit.push_back(receiveInf());//text 1024 未输入 } sendInf("n"); receiveInf();//保证程序正常运行 break; } MysqlOperation::useQuery(mysql, "update `" + subName + "test` set type = '" + testEdit[0] + "', topic = '" + testEdit[1] + "', score = '" + testEdit[2] + "', answer = '" + testEdit[3] + "' where `id` = '" + number + "'"); sendInf("修改成功"); receiveInf();//保证程序正常运行 } } //删除题目 static void deleteSubject() { MYSQL* mysql = &localMysql; sendInf("请输入要修改删除试题的考试名称: "); std::string subName = receiveInf(); MysqlOperation::useQuery(mysql, "show tables"); MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row; bool flags = false; while (row = mysql_fetch_row(result)) { if (row[0] == subName) { flags = true; break; } } mysql_free_result(result); if (!flags) { sendInf("false"); } else { sendInf("true"); } receiveInf();//保证程序正常运行 if (!flags) { sendInf("没有该科目试卷"); receiveInf();//保证程序正常运行 } else { sendInf("当前试卷如下n"); receiveInf();//保证程序正常运行 MysqlOperation::useQuery(mysql, "select * from `" + subName + "test`"); result = mysql_store_result(mysql); int rnum = mysql_num_fields(result); std::string ans; while (row = mysql_fetch_row(result)) { for (int i = 0; i < rnum; i++) { if (i == 0) ans += "序号:"; if (i == 1) { std::string ri = row[i]; if (ri == "1") { ans += "类型:选择 代号:"; } else if (ri == "2") { ans += "类型:填空 代号:"; } else if (ri == "3") { ans += "类型:大题 代号:"; } } else if (i == 2) ans += "题目:n"; else if (i == 3) ans += "分值:"; else if (i == 4) ans += "答案:"; ans += row[i]; ans += "n"; } ans += "n"; } sendInf(ans);//送出试卷 receiveInf();//保证程序正常运行 sendInf("请选择要删除的题目编号"); std::string number = receiveInf();//保证程序正常运行 MysqlOperation::useQuery(mysql, "delete from `" + subName + "test` where id = '" + number + "'"); } } //考试报名 static void signUp(std::vector<std::string> userInf) { MYSQL* mysql = &localMysql; std::string oper = "select `subName`, `time` from `subject` where `subName` is not null"; bool res = MysqlOperation::useQuery(mysql, oper); if (res) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (res) { MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row; std::vector<std::string> subjectList; std::vector<std::string> timeList; while (row = mysql_fetch_row(result)) { subjectList.push_back(row[0]); timeList.push_back(row[1]); } mysql_free_result(result); sendInf("当前存在的考试科目及时间如下:n"); receiveInf();//保证程序正常运行 int i = 0; std::string low; for (auto& j : subjectList) { ++i; low = low + std::to_string(i) + ": " + j + "n" + "时间:n" + timeList[i - 1] + "nn"; } sendInf(low); receiveInf();//保证程序正常运行 sendInf("请输入要报名的序号: "); std::string serial = receiveInf();//num 2 de -1 int se = (int)strToLf(serial); bool lowss = se > subjectList.size() || se < 1; if (lowss) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (lowss) { sendInf("没有该考试信息!n"); receiveInf();//保证程序正常运行 return; } else { oper = "select `studentAccont` from `" + subjectList[se - 1] + "` where studentAccont = '" + userInf[1] + "'"; res = MysqlOperation::useQuery(mysql, oper); if (res) { MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); if (row) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (row) { sendInf("当前考试您已报名n"); receiveInf();//保证程序正常运行 return; } mysql_free_result(result); } oper = "select `id`, `name`, `major`, `grade`, `class`, `accont` from student where accont = '" + userInf[1] + "'"; res = MysqlOperation::useQuery(mysql, oper); if (res) { MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); int field = mysql_num_fields(result); std::vector<std::string> oneStudent; std::string id = row[0]; for (int i = 1; i < field; i++) { oneStudent.push_back(row[i]); } mysql_free_result(result); std::vector< std::vector<std::string>> studentList; studentList.push_back(oneStudent); std::vector<std::string> fieldList = { "studentName", "studentMajor","studentGrade","studentClass", "studentAccont" }; if (MysqlOperation::addData(subjectList[se - 1], fieldList, studentList)) { std::vector<std::string> fieldList2 = { "id", "accont","subjectName" }; std::vector<std::string> data = { id,userInf[1],subjectList[se - 1] }; std::vector< std::vector<std::string>> dataIn = { data }; MysqlOperation::addData("entryForm", fieldList2, dataIn); MysqlOperation::addField("student", subjectList[se - 1] + "Score", "double", "", "", ""); sendInf("报名成功n"); receiveInf();//保证程序正常运行 } else { sendInf("报名失败n"); receiveInf();//保证程序正常运行 } } } } } //开始考试 static void beginTest(std::vector<std::string> userInf) { MYSQL* mysql = &localMysql; std::string oper = "select subjectName from `entryForm` where accont = '" + userInf[1] + "'"; bool res = MysqlOperation::useQuery(mysql, oper); if (res) { MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); if (!row) sendInf("false"); else sendInf("true"); receiveInf();//保证程序正常运行 if (!row) { sendInf("您当前未报名任何考试!n"); receiveInf();//保证程序正常运行 } else { std::vector<std::string>nameList; while (row) { nameList.push_back(row[0]); row = mysql_fetch_row(result); } mysql_free_result(result); sendInf("以下当前报名的考试n"); receiveInf();//保证程序正常运行 std::string sendss; for (int i = 0; i < nameList.size(); i++) { sendss = sendss + std::to_string(i + 1) + ":" + nameList[i] + "n"; } sendInf(sendss);//送出已报名的考试列表 receiveInf();//保证程序正常运行 sendInf("请输入要参加考试的序号:n"); std::string se = receiveInf();//num 5 de -1 sendInf(std::to_string(nameList.size()));//送出考试数量 receiveInf();//保证程序正常运行 if (strToLf(se) < 1 || strToLf(se) > nameList.size()) { sendInf("没有该选项n"); receiveInf();//保证程序正常运行 } else { int sea = (int)strToLf(se); std::string oper = "show tables"; res = MysqlOperation::useQuery(mysql, oper); result = mysql_store_result(mysql); bool have = false; while (row = mysql_fetch_row(result)) { if (row[0] == nameList[sea - 1] + "test") { have = true; break; } } mysql_free_result(result); if (!have) sendInf("false"); else sendInf("true"); receiveInf();//保证程序正常运行 if (!have) { sendInf("当前考试老师还没有添加试卷n"); receiveInf();//保证程序正常运行 } else { std::vector<double> scoreList(4); std::string oper = "select `id`, `type`, `topic`, `score`, `answer` from `" + nameList[sea - 1] + "test`"; std::vector<std::vector<std::string>> testPaper; MysqlOperation::useQuery(mysql, oper); result = mysql_store_result(mysql); row = mysql_fetch_row(result); while (row) { std::vector<std::string> subs; for (int i = 0; i < 5; i++) { subs.push_back(row[i]); } testPaper.push_back(subs); row = mysql_fetch_row(result); } mysql_free_result(result); std::vector<int> randomSubject = createRandList(1, testPaper.size()); sendInf(std::to_string(randomSubject.size()));//送出试题数量 receiveInf();//保证程序正常运行 for (int i = 0; i < randomSubject.size(); i++) { std::string lows = "n题目 " + std::to_string(i + 1) + ":n" + testPaper[randomSubject[i] - 1][2] + "n" + "该题分值: " + testPaper[randomSubject[i] - 1][3] + "n"; sendInf(lows); receiveInf();//保证程序正常运行 std::string answers; sendInf(testPaper[randomSubject[i] - 1][1]);//送出试题类型 receiveInf();//保证程序正常运行 if (testPaper[randomSubject[i] - 1][1] == "1") { sendInf("请输入选项: "); answers = receiveInf();//string 15 de 未输入 std::transform(answers.begin(), answers.end(), answers.begin(), ::toupper); if (testPaper[randomSubject[i] - 1][4] == answers) { scoreList[0] += strToLf(testPaper[randomSubject[i] - 1][3]); scoreList[3] += strToLf(testPaper[randomSubject[i] - 1][3]); } } else if (testPaper[randomSubject[i] - 1][1] == "2") { sendInf("请输入答案,输入完成后另起一行输入~~~上传答案 "); answers = receiveInf();//string 500 ed 未输入 if (testPaper[randomSubject[i] - 1][4] == answers) { scoreList[1] += strToLf(testPaper[randomSubject[i] - 1][3]); scoreList[3] += strToLf(testPaper[randomSubject[i] - 1][3]); } } else { sendInf("请输入答案,输入完成后另起一行输入~~~上传答案 "); answers = receiveInf();//text 1024 未输入 if (testPaper[randomSubject[i] - 1][4] == answers) { scoreList[2] += strToLf(testPaper[randomSubject[i] - 1][3]); scoreList[3] += strToLf(testPaper[randomSubject[i] - 1][3]); } } } sendInf("正在记录成绩...n"); receiveInf();//保证程序正常运行 std::vector<std::string> fieldList = { nameList[sea - 1] + "Score" }; std::vector<std::string> sc = { lfToStr(scoreList[3]) }; MysqlOperation::modifyData("student", fieldList, sc, " accont = '" + userInf[1] + "'"); MysqlOperation::addData(nameList[sea - 1], std::vector<std::string>{"studentName", "studentMajor", "studentGrade", "studentClass", "studentAccont", "score"}, std::vector<std::vector<std::string>>{std::vector<std::string>{userInf[2], userInf[3], userInf[4], userInf[5], userInf[1], lfToStr(scoreList[0] + scoreList[1] + scoreList[2])}}); sendInf("记录完成!nn"); receiveInf();//保证程序正常运行 std::string lowss = "n考试已完成, 题目已由系统批改,其中:n选择题得分: " + std::to_string(scoreList[0]) + "n" + "填空题得分: " + std::to_string(scoreList[1]) + "n" + "大题得分: " + std::to_string(scoreList[2]) + "nn" + "总分: " + std::to_string(scoreList[3]) + "nn" + "填空题,大题部分由于本系统的无能或许会出现误判,请n等待老师手动重批,以上成绩仅供参考n"; sendInf(lowss); receiveInf();//保证程序正常运行 } } } } } //查看成绩 static void checkResult(std::vector<std::string> userInf) { MYSQL* mysql = &localMysql; MYSQL_RES* result; MYSQL_ROW row; std::string oper; std::vector<std::string> subjectName; oper = "select subjectName from `entryForm` where accont = '" + userInf[1] + "'"; bool res = MysqlOperation::useQuery(mysql, oper); if (res) { result = mysql_store_result(mysql); while (row = mysql_fetch_row(result)) { subjectName.push_back(row[0]); } mysql_free_result(result); } oper = "select "; for (int i = 0; i < subjectName.size(); i++) { oper = oper + "`" + subjectName[i] + "Score`"; if (i < subjectName.size() - 1) { oper += ","; } } oper = oper + " from student where accont = '" + userInf[1] + "'"; res = MysqlOperation::useQuery(mysql, oper); if (res) { result = mysql_store_result(mysql); MYSQL_FIELD* field; std::string low; while (field = mysql_fetch_field(result)) { low += field->name; low += "t"; } sendInf(low); receiveInf();//保证程序正常运行 int column = mysql_num_fields(result); std::string ans; MYSQL_ROW row = mysql_fetch_row(result); while (row) { for (int i = 0; i < column; i++) { if (row[i]) { ans += row[i]; } else { ans += "null"; } if (i < column - 1) { ans += "t"; if (i >= 7) { ans += "t"; } } } ans += "n"; row = mysql_fetch_row(result); } sendInf(ans); receiveInf();//保证程序正常运行 mysql_free_result(result); } } }; class User { public: //登录 static std::vector<std::string> signIn() { MYSQL* mysql; MYSQL_RES* result; MYSQL_ROW password; std::vector<std::string> re; while (true) { std::string sendOut = R"( 登录: 请选择身份: 1 教师 2 学生 请输入序号:)"; sendInf(sendOut);//送出身份选择 std::string order = receiveInf();//获得身份 re.push_back(order);//储存身份 std::vector<std::string> inf; sendInf("server: 请输入账号:"); inf.push_back(receiveInf());//获得账号 string 20 sendInf("server: 请输入密码:"); inf.push_back(receiveInf());//获得密码 string 15 mysql = &localMysql; std::string tors = "student"; if (order == "1") tors = "teacher"; std::string oper = "select `password` from `" + tors + "` where accont = '" + inf[0] + "'"; bool res = MysqlOperation::useQuery(mysql, oper); result = mysql_store_result(mysql); password = mysql_fetch_row(result); std::string iferror = "false"; if (!password) { iferror = "true"; } sendInf(iferror);//发送错误情况 receiveInf();//保证正常运行 if (!password) { mysql_free_result(result); sendInf("server: 用户不存在,是否要创建账户? 1:创建 2:取消 请输入序号:"); std::string ins = receiveInf();//获得选择 if (ins == "1") { userCreate(); } continue; } else { bool ifR = password[0] == inf[1]; if (ifR) sendInf("true"); else sendInf("false"); receiveInf();//保证正常运行 if (ifR) { mysql_free_result(result); bool low = MysqlOperation::useQuery(mysql, "select `accont`, `name`, `major`, `grade`, `class` from `student` where accont = '" + inf[0] + "'"); if (low) sendInf("true");//送出查询情况 else sendInf("false");//送出查询情况 receiveInf();//保证正常运行 if (low) { result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); if (row) { for (int i = 0; i < 5; i++) { re.push_back(row[i]); } } mysql_free_result(result); sendInf("server: 登陆成功!");//送出选择 receiveInf();//保证正常运行 return re; } else { sendInf("server: 登陆失败!");//送出选择 receiveInf();//保证正常运行 continue; } } else { sendInf("server: 账号或密码错误"); receiveInf();//保证正常运行 continue; } } } } //创建用户 static void userCreate() { sendInf(R"( 请选择身份: 1 教师 2 学生 请输入序号:)"); std::string order = receiveInf();//获得身份 std::vector<std::string> inf; sendInf("server: 请输入姓名:"); inf.push_back(receiveInf());//获得姓名,string 20 sendInf("server: 请输入专业:"); inf.push_back(receiveInf());//获得专业,string 20 if (order == "2") { sendInf("server: 请输入年级:"); inf.push_back(receiveInf());//获得年级,int 2 sendInf("server: 请输入班级:"); inf.push_back(receiveInf());//获得班级 int 2 } sendInf("server: 请输入电话:"); inf.push_back(receiveInf());//string 11 sendInf("server: 请输入账号:"); inf.push_back(receiveInf());//string 20 sendInf("server: 请输入密码:"); inf.push_back(receiveInf());//string 15 std::string tors = "student"; if (order == "1") tors = "teacher"; MYSQL* mysql = &localMysql; std::string oper = "select * from `" + tors + "` where accont = " + inf[3]; bool res = MysqlOperation::useQuery(mysql, oper); if (res) sendInf("true");//送出查询情况 else sendInf("false");//送出查询情况 receiveInf();//保证正常运行 if (res) { MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW accont = mysql_fetch_row(result); std::string ifExit = "false"; if (accont) { ifExit = "true"; } sendInf(ifExit);//送出账号是否存在的状态 receiveInf();//保证正常运行 if (accont) { sendInf("server: 用户已存在!"); receiveInf();//保证正常运行 } else { std::vector<std::string> field; field.push_back("name"); field.push_back("major"); if (order == "2") { field.push_back("grade"); field.push_back("class"); } field.push_back("phone"); field.push_back("accont"); field.push_back("password"); std::vector<std::vector<std::string>> infIn; infIn.push_back(inf); bool res = MysqlOperation::addData(tors, field, infIn); if (res) { sendInf("server: 创建成功!"); receiveInf();//保证正常运行 } else { sendInf("server: 创建失败!"); receiveInf();//保证正常运行 } } mysql_free_result(result); } else { std::cout << mysql_error(mysql) << std::endl; } } //修改用户 static void modifyUser() { MYSQL* mysql = &localMysql; sendInf("请输入要修改的用户的身份:n1:教师n2:学生n请输入:"); std::string orders = receiveInf(); if (orders == "1") { orders = "teacher"; } else { orders = "student"; } sendInf("请输入要修改的用户账号:n"); std::string accont = receiveInf(); MysqlOperation::useQuery(mysql, "select * from `" + orders + "` where accont = '" + accont + "'"); MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); if (row) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (!row) { sendInf("未找到该用户...n"); receiveInf();//保证程序正常运行 } else { sendInf("已找到该用户:n"); receiveInf();//保证程序正常运行 std::string fieldList; std::string datas; std::vector<std::string> infList; MYSQL_FIELD* field; while (field = mysql_fetch_field(result)) { fieldList += field->name; fieldList += "t"; } fieldList += "n"; int fnum = mysql_num_fields(result); while (row) { for (int i = 0; i < fnum; i++) { infList.push_back(row[i]); datas = datas + row[i] + "t"; } row = mysql_fetch_row(result); } mysql_free_result(result); datas += "n"; sendInf(fieldList + datas);//送出当前用户信息 receiveInf();//保证程序正常运行 sendInf("请开始修改以下信息,不修改的按回车跳过: n"); receiveInf();//保证程序正常运行 std::vector<std::string> dataList; sendInf(infList[1]);//送出老姓名 receiveInf();//保证程序正常运行 sendInf("姓名:"); dataList.push_back(receiveInf());//获得新姓名 sendInf(infList[2]);//送出老专业 receiveInf();//保证程序正常运行 sendInf("专业:"); dataList.push_back(receiveInf());//获得新专业 if (orders == "student") { sendInf(infList[3]);//送出老年级 receiveInf();//保证程序正常运行 sendInf("年级:"); dataList.push_back(receiveInf());//获得新年级 sendInf(infList[4]);//送出老班级 receiveInf();//保证程序正常运行 sendInf("班级:"); dataList.push_back(receiveInf());//获得新班级 sendInf(infList[5]);//送出老电话 receiveInf();//保证程序正常运行 sendInf("电话:"); dataList.push_back(receiveInf());//获得新电话 sendInf(infList[6]);//送出老账号 receiveInf();//保证程序正常运行 sendInf("账号:"); dataList.push_back(receiveInf());//获得新账号 sendInf(infList[7]);//送出老密码 receiveInf();//保证程序正常运行 sendInf("密码:"); dataList.push_back(receiveInf());//获得新密码 MysqlOperation::useQuery(mysql, "update `" + orders + "` set `name` = '" + dataList[0] + "', `major` = '" + dataList[1] + "', `grade` = '" + dataList[2] + "', `class` = '" + dataList[3] + "', `phone` = '" + dataList[4] + "', `accont` = '" + dataList[5] + "', `password` = '" + dataList[6] + "' where `accont` = '" + accont + "'"); } else { sendInf(infList[3]);//送出老电话 receiveInf();//保证程序正常运行 sendInf("电话:"); dataList.push_back(receiveInf());//获得新电话 sendInf(infList[4]);//送出老账号 receiveInf();//保证程序正常运行 sendInf("账号:"); dataList.push_back(receiveInf());//获得新账号 sendInf(infList[5]);//送出老密码 receiveInf();//保证程序正常运行 sendInf("密码:"); dataList.push_back(receiveInf());//获得新密码 MysqlOperation::useQuery(mysql, "update `" + orders + "` set `name` = '" + dataList[0] + "', `major` = '" + dataList[1] + "', `phone` = '" + dataList[2] + "', `accont` = '" + dataList[3] + "', `password` = '" + dataList[4] + "' where `accont` = '" + accont + "'"); } sendInf("修改完成");//送出信息 receiveInf();//保证程序正常运行 } } //删除用户 static void deleteUser() { MYSQL* mysql = &localMysql; sendInf("请输入要删除的用户的身份:n1:教师n2:学生n请输入:"); std::string orders = receiveInf(); if (orders == "1") { orders = "teacher"; } else { orders = "student"; } sendInf("请输入要删除的用户账号:n"); std::string accont = receiveInf(); MysqlOperation::useQuery(mysql, "select * from `" + orders + "` where accont = '" + accont + "'"); MYSQL_RES* result = mysql_store_result(mysql); MYSQL_ROW row = mysql_fetch_row(result); if (row) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (!row) { sendInf("未找到该用户...n"); receiveInf();//保证程序正常运行 } else { sendInf("已找到该用户:n"); receiveInf();//保证程序正常运行 std::string fieldList; std::string datas; std::vector<std::string> infList; MYSQL_FIELD* field; while (field = mysql_fetch_field(result)) { fieldList += field->name; fieldList += "t"; } fieldList += "n"; int fnum = mysql_num_fields(result); while (row) { for (int i = 0; i < fnum; i++) { infList.push_back(row[i]); datas = datas + row[i] + "t"; } row = mysql_fetch_row(result); } mysql_free_result(result); datas += "n"; sendInf(fieldList + datas);//送出当前用户信息 receiveInf();//保证程序正常运行 sendInf("是否删除? 1:是 2:否 请输入选择:");//送出当前用户信息 std::string ifd = receiveInf(); if (ifd == "1") { MysqlOperation::useQuery(mysql, "delete from `" + orders + "` where accont = '" + accont + "'"); sendInf("删除完成n"); receiveInf();//保证程序正常运行 } else { sendInf("取消删除n"); receiveInf();//保证程序正常运行 } } } }; bool flagss = true; //界面与登录 class Visualization { public: //初始化 static void initialization() { system("color E1"); std::cout << "正在初始化系统..." << std::endl; std::string DBname = "ExaminationSystem"; MysqlOperation useSql; useSql.ConnectDB("localhost", "root", "@Shang123", "mysql", 3306); useSql.checkIfConnectDB(); std::cout << "正在创建基础表结构..." << std::endl; useSql.createTable("teacher", "id", "int", "primary key", "auto_increment", "序号", "教师信息"); useSql.createTable("student", "id", "int", "primary key", "auto_increment", "序号", "学生信息"); useSql.createTable("subject", "id", "int", "primary key", "auto_increment", "序号", "考试科目"); useSql.createTable("entryForm", "id", "int", "", "", "学生序号", "考试科目"); useSql.addField("teacher", "name", "varchar(20)", "", "", "姓名"); useSql.addField("teacher", "major", "varchar(20)", "", "", "专业"); useSql.addField("teacher", "phone", "char(11)", "", "", "电话"); useSql.addField("teacher", "accont", "varchar(20)", "", "", "账号"); useSql.addField("teacher", "password", "varchar(15)", "", "", "密码"); useSql.addField("student", "name", "varchar(20)", "", "", "姓名"); useSql.addField("student", "major", "varchar(20)", "", "", "专业"); useSql.addField("student", "grade", "int", "", "", "年级"); useSql.addField("student", "class", "int", "", "", "班级"); useSql.addField("student", "phone", "char(11)", "", "", "电话"); useSql.addField("student", "accont", "varchar(20)", "", "", "账号"); useSql.addField("student", "password", "varchar(15)", "", "", "密码"); useSql.addField("subject", "subName", "varchar(50)", "", "", "科目名"); useSql.addField("subject", "fullScore", "int", "", "", "分值"); useSql.addField("subject", "time", "varchar(500)", "", "", "考试时间表"); useSql.addField("entryForm", "accont", "varchar(20)", "", "", "学生账号"); useSql.addField("entryForm", "subjectName", "varchar(50)", "", "", "报名科目"); std::cout << "创建成功..." << std::endl; std::cout << "初始化完成!" << std::endl; system("pause"); } //开始界面 static void begin(std::string identity) { if (identity == "2") { sendInf(R"( ?---------------0-0-0---------------? | | | 欢迎使用 好果zhi考试系统 | | 本系统暂时没什么要给你说的... | | 功能指令如下: | | 1 登录 | | 2 创建用户 | | 3 考试报名 | | 4 进行考试 | | 5 查看成绩 | | 6 离开系统 | | author:阿白 | | 2022/10/26 | |___________________________________| )"); receiveInf();//保证正常运行 } else { sendInf(R"( ?---------------(>v<)---------------? | | | 欢迎使用 好果zhi考试系统 | | 本系统暂时没什么要给你说的... | | 功能指令如下: | | 1 登录 | | 2 创建用户 | | 3 修改用户 | | 4 删除用户 | | 5 设置考试 | | 6 创建试卷 | | 7 添加试题 | | 8 修改试题 | | 9 删除试题 | | 0 离开系统 | | author:阿白 | | 2022/10/26 | |___________________________________| )"); receiveInf();//保证正常运行 } } static std::string end() {//告别界面 sendInf(R"( !---------------(=_=)---------------! | | | 就要告别了呢... | | ... | | 考试不快乐吗 | | 还是本系统不好用呢 | | | | ########################### | | ########################### | | ...好吧 | | 期待下次相见 | | >_< | |___________________________________| )"); return receiveInf();//服务端是否要求主机关机 } //登录界面 static std::vector<std::string> signInVisual() { std::vector<std::string> userInf; while (true) { std::string face = R"( ←---------------------- UnU ----------------------→ ` 注意: ` ` ` ` 在使用这个考试系统前,本系统要验证一下你的身份!` ` 所以: ` ` ` ` 请先:1 登录 2 注册 ` 请输入序号:)"; sendInf(face); std::string useMySystem = receiveInf();//获得选择 if (useMySystem == "1") { userInf = User::signIn(); flagss = false; } else { User::userCreate(); continue; } if (userInf.empty()) sendInf("true"); else sendInf("false"); receiveInf();//保证程序正常运行 if (userInf.empty()) { continue; } break; } return userInf; } }; //子线程 DWORD WINAPI realize(LPVOID); bool ts = false; //socket初始化 bool socInitlz() { WSADATA* wsaData = &localWsaData; int res; if (!WSAStartup(MAKEWORD(2, 2), wsaData)) { std::cout << "绑定socket库成功" << std::endl; } else { std::cout << "绑定socket库失败" << std::endl; return false; } if (2 != LOBYTE(localWsaData.wVersion) || 2 != HIBYTE(localWsaData.wVersion)) { WSACleanup(); std::cout << "WSADATA的版本不正确" << std::endl; return false; } //创建套接字 serverSocket = socket(AF_INET, SOCK_STREAM, 0); //绑定套接字,配置监听地址和端口 SOCKADDR_IN svrAddr; ZeroMemory((char*)&svrAddr, sizeof(svrAddr)); svrAddr.sin_family = AF_INET; //国际网区域 svrAddr.sin_port = htons(6000); //监听端口 svrAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //有IP if (::bind(serverSocket, (SOCKADDR*)&svrAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) { std::cout << "配置监听失败: " << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); return false; } //监听 if (::listen(serverSocket, 10) == SOCKET_ERROR) {//最大连接数10个 std::cout << "system: 开启监听失败 " << WSAGetLastError() << std::endl; closesocket(serverSocket); WSACleanup(); return false; } std::cout << "system: 开启监听成功n"; //接收套接字 SOCKADDR_IN clientAddr; int length = sizeof(SOCKADDR); //接收连接 if ((connectSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &length)) == INVALID_SOCKET) { std::cout << "system: 接收消息失败" << WSAGetLastError() << std::endl; closesocket(connectSocket); WSACleanup(); return false; } HANDLE sendThread = CreateThread(nullptr, 0, realize, 0, 0, nullptr); if (sendThread) { CloseHandle(sendThread); } hMUTEX = CreateMutex(NULL, FALSE, L"mutex"); while (true) { if (ts) { std::cout << "客户端请求终止服务..."; break; } Sleep(100); } closesocket(serverSocket); closesocket(connectSocket); WSACleanup(); return true; } int main() { Visualization::initialization(); system("cls"); socInitlz();//初始化服务端并使用线程 return 0; } DWORD WINAPI realize(LPVOID) { std::vector<std::string> userInf; if (flagss) {//只有第一次使用该程序时调用 userInf = Visualization::signInVisual(); } sendInf(userInf[0]);//传递身份 receiveInf();//保证程序正常运行 while (true) { Visualization::begin(userInf[0]); sendInf("请输入您的指令: "); std::string ins = receiveInf();//获得指令 if (ins == "1") {//登录 userInf = User::signIn(); } else if(ins == "2") {//注册 User::userCreate(); } else if (ins == "3") { if (userInf[0] == "1") { User::modifyUser();//修改用户 } else { Test::signUp(userInf);//考试报名 } } else if (ins == "4") { if (userInf[0] == "1") { User::deleteUser();//删除用户 } else { Test::beginTest(userInf);//开始考试 } } else if(ins == "5") { if (userInf[0] == "1") { //创建考试 Test::setTest(); } else { Test::checkResult(userInf);//查看成绩 } } else if (ins == "6") { if (userInf[0] == "1") { Test::createTest();//创建试卷 } else { Visualization::end();//告别系统 ts = true; return 0; } } else if (ins == "7") { //添加试题 sendInf("请输入要添加题目的试卷名称:"); std::string subname = receiveInf();//string 50 未输入 Test::addSubject(subname + "test"); } else if (ins == "8") { Test::modifySubject();//修改试题 } else if (ins == "9") { Test::deleteSubject();//删除试题 } else { Visualization::end(); ts = true; return 0; } } }
2.客户端的创建
头文件的添加同服务端
代码:
#include "stdafx.h" //便捷读取 class SafeRead { public: //录入数字 static std::string readNum(int length, const std::string& oldNum) { std::string inf; //label位置 label:while (true) { std::cout << " 请输入数字:"; getline(std::cin, inf); if (inf == "n" || inf.empty()) { return oldNum; } else if ((int)inf.length() > length) { std::cout << "nt长度超过" << length << "位(计算需要包含小数点),请重新输入。n"; continue; } std::stringstream sin(inf); double d; char c; bool flag = true; if (!(sin >> d)) flag = false; if (sin >> c) flag = false; if (!flag) { std::cout << "输入的不是一个数字,请重新输入" << std::endl; continue; } break; } //删除前导零 std::string::iterator it = inf.begin(); for (unsigned int i = 0; i < inf.length() - 1; i++) {//单0不删,一串0只留一个 if (inf[i] == '-') continue; if (inf[i] != '0') break; if (inf[i] == '0' && inf[i + 1] == '.') break; inf.erase(it); it++; } return inf; } //录入有限制的字符串,用于读取基本信息 static std::string readString(int length, std::string old) { std::string inf; while (true) { getline(std::cin, inf); if (inf == "n" || inf.empty()) { return old; } else if ((int)inf.length() > length) { std::cout << "nt信息长度超过" << length << ",请重新输入。n"; continue; } return inf; } } //读取文本块,以~~~结束 static std::string readText(int length, std::string old) { while (true) { std::string ans; while (true) { std::string inf; getline(std::cin, inf); if (inf == "~~~") { break; } else { ans = ans + inf + "n"; } } if (ans.size() > length) { std::cout << "当前文本长度(包括空格)为 " << ans.size() << ",已超过限定长度 " << length << ",请重新输入..." << std::endl; continue; } return ans; } } }; double strToLf(const std::string& number) { double lf = 0, lfi = 0, x = 10; int i = 0, f = 1, times = 1, length = (int)number.length(); while (number[i] < '0' || number[i] > '9') {//跳过可能存在的¥,$ 或 - i++; if (number[i] == '-') f *= -1; } //整数位 while (i < length) { if (number[i] == '.') { break; } lf = lf * 10 + number[i] - '0'; i++; } //小数位,++i跳过‘ . ’ while (++i < length) { lfi += (number[i] - '0') / x; x *= 10; } return times * f * (lf + lfi); } WSADATA localWsaData; SOCKET clientSocket; HANDLE hMUTEX; DWORD WINAPI realize(LPVOID); using std::cout; using std::endl; int sendInf(std::string sendBuff); std::string receiveInf(); void rev(); void createUser(); std::string signIn(); void setTest(); void createTest(); void addSubject(); void signUp(); void beginTest(); void checkResult(); void modifySubject(); void deleteSubject(); void modifyUser(); void deleteUser(); //客户端线程 DWORD WINAPI realize(LPVOID); bool ts = false; int main() { WSADATA* wsaData = &localWsaData; if (WSAStartup(MAKEWORD(1, 1), wsaData)) { std::cout << "加载WinSock错误" << std::endl; return false; } else { std::cout << "加载WinSock成功" << std::endl; } if (LOBYTE(localWsaData.wVersion) != 1 || HIBYTE(localWsaData.wVersion) != 1) { WSACleanup(); return false; } //创建套接字 clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (clientSocket == INVALID_SOCKET) { std::cout << "套接字库创建失败" << std::endl; } else { std::cout << "套接字库创建成功" << std::endl; } //与服务端连接 SOCKADDR_IN svrAddr; svrAddr.sin_family = AF_INET; //国际网区域 svrAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//服务端IP svrAddr.sin_port = htons(6000); //监听端口 if (connect(clientSocket, (SOCKADDR*)&svrAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) { std::cout << "连接错误: " << WSAGetLastError() << std::endl; closesocket(clientSocket); WSACleanup(); return false; } std::cout << "连接服务端成功" << std::endl; //创建子线程 HANDLE sendThread = CreateThread(nullptr, 0, realize, 0, 0, nullptr); if (sendThread) { CloseHandle(sendThread); } hMUTEX = CreateMutex(NULL, FALSE, reinterpret_cast<LPCSTR>(L"mutex")); //给予线程使用 while (true) { if (ts) { return 0; } Sleep(100); } closesocket(clientSocket); WSACleanup(); return 0; } bool flag = false; DWORD WINAPI realize(LPVOID) { system("color E1"); while (!flag) { system("cls"); std::string order; rev();//获取开始登录界面 std::string ins = SafeRead::readNum(1, "1"); sendInf(ins);//送出选择 if (ins == "1") { signIn(); flag = true; } else { createUser(); system("pause"); continue; } std::string ifempty = receiveInf(); sendInf("");//保证程序正常运行 if (ifempty == "true") { continue; } system("pause"); break; } std::string userInf = receiveInf();//获得身份 sendInf("");//保证程序正常运行 while (true) { system("cls"); rev();//获得开始界面 sendInf("");//保证程序正常运行 rev();//请输入您的指令提醒 std::string inf = SafeRead::readNum(1, "1"); sendInf(inf);//送出指令 if (inf == "1") {//登录 userInf = signIn(); } else if (inf == "2") { createUser(); } else if (inf == "3") { if (userInf == "1") { modifyUser(); } else { signUp();//考试报名 } } else if (inf == "4") { if (userInf == "1") { deleteUser(); } else { beginTest();//开始考试 } } else if (inf == "5") { if (userInf == "1") { setTest();//设置考试 } else { checkResult();//查看成绩 } } else if (inf == "6") { if (userInf == "1") { createTest();//创建试卷 } else { rev();//获得告别界面 sendInf("1");//由于现在只连一个客户端,直接让服务端也关闭算了 ts = true; system("pause"); return 0; } } else if (inf == "7") { rev();// sendInf(SafeRead::readString(50, "未输入"));//输入试卷名 addSubject();//添加试题 } else if (inf == "8") { modifySubject();//修改试题 } else if(inf == "9") { deleteSubject();//删除试题 } else { rev();//获得告别界面 sendInf("1");//由于现在只连一个客户端,直接让服务端也关闭算了 ts = true; system("pause"); return 0; } system("pause"); } } int sendInf(std::string sendBuff) { sendBuff += ''; if (sendBuff == "#") { sendBuff = "system: 用户端请求终止对话...n"; } int ret = send(clientSocket, sendBuff.c_str(), sizeof(char) * sendBuff.size(), 0); if (ret == SOCKET_ERROR) { std::cout << "system: 发送失败: " << WSAGetLastError() << std::endl; closesocket(clientSocket); WSACleanup(); return -1; } else if (ret == 0) { std::cout << "system: 服务端断开连接: " << std::endl; closesocket(clientSocket); WSACleanup(); return 0; } else { return 1; } } std::string receiveInf() { char recvBuff[3000]{}; int flag = recv(clientSocket, recvBuff, 3000, 0); if (flag == SOCKET_ERROR) { std::cout << "system: 接收消息失败: " << WSAGetLastError(); closesocket(clientSocket); WSACleanup(); return ""; } else if (!flag) { std::cout << "system: 服务端断开连接: " << WSAGetLastError(); closesocket(clientSocket); WSACleanup(); return ""; } return recvBuff; } void rev() {//简化需要直接输出的接收数据 cout << receiveInf() << endl; } //登录 std::string signIn() { while (true) { std::string order; rev();//获取身份选择界面 order = SafeRead::readNum(1, "1");//选择身份 1 教师 2 学生 sendInf(order); rev();//接收身份报错 sendInf(SafeRead::readString(20, "未输入"));//送出账号 最长20 rev();//保证正常运行 sendInf(SafeRead::readString(15, "未输入"));//送出密码 最长15 std::string iferror = receiveInf();//接收错误情况 sendInf("");//保证正常运行 if (iferror == "true") { rev();//接收是否需要现在创建用户的选择 1 创建 2 不创建 std::string ifc = SafeRead::readNum(1, "2"); sendInf(ifc);//送出选择 if (ifc == "1") { createUser(); } continue; } else { std::string ifR = receiveInf();//接收密码是否正确的情况 sendInf("");//保证正常运行 if (ifR == "true") { std::string low = receiveInf();//接收查询情况 sendInf("");//保证正常运行 if (low == "true") { rev();//接收登陆成功提醒 sendInf("");//保证正常运行 return order; } else { rev();//接收登录失败提醒 sendInf("");//保证正常运行 continue; } } else { rev();//接收密码错误的提示 sendInf("");//保证正常运行 continue; } } } } void createUser() { rev();//获得身份选择界面 std::string order = SafeRead::readNum(1, "1");//做出身份选择 sendInf(order); rev();//提示输入姓名 sendInf(SafeRead::readString(20, "未输入"));//送出姓名 rev(); sendInf(SafeRead::readString(20, "未输入"));//送出专业 if (order == "2") { rev(); sendInf(SafeRead::readNum(2, "-1"));//送出年级 rev(); sendInf(SafeRead::readNum(2, "-1"));//送出班级 } rev(); sendInf(SafeRead::readString(11, "未输入"));//送出电话 rev(); sendInf(SafeRead::readString(20, "未输入"));//送出账号 rev(); sendInf(SafeRead::readString(15, "未输入"));//送出密码 std::string ins = receiveInf();//接收搜索状态 sendInf("");//保证正常运行 if (ins == "true") { std::string low = receiveInf(); sendInf("");//保证正常运行 if (low == "true") {//判断账号是否存在的搜索//保证正常运行 rev();//接收账号已存在的反馈 sendInf("");//保证正常运行 } else { rev();//打印创建反馈 sendInf("");//保证正常运行 } } else { cout << "n创建出现错误" << endl; } } void setTest() { rev(); sendInf(SafeRead::readString(50, "未输入"));//传递考试科目 rev(); sendInf(SafeRead::readNum(5, "-1"));//传递考试分值 rev(); sendInf(SafeRead::readText(500, "未输入"));//传递考试时间表 std::string low = receiveInf();//接收res sendInf("");//保证程序正常运行 if (low == "true") { rev();//接收设置成功的消息 sendInf("");//保证程序正常运行 } } void createTest() { rev(); sendInf(SafeRead::readString(50, "未输入"));//传递考试科目 std::string low = receiveInf();//接收res sendInf("");//保证程序正常运行 if (low == "true") { std::string res = receiveInf();//接收该科目考试是否为空的消息 sendInf("");//保证程序正常运行 if (res == "true") { rev();//接收现在是否设置考试的消息 1 设置 2 不设置 std::string lows = SafeRead::readNum(1, "2"); sendInf(lows);//传递选择 if (lows == "1") { setTest(); } else { return; } } else { addSubject(); } } } void addSubject() { rev();//接收请开始添加试题的提示 sendInf("");//保证程序正常运行 while (true) { std::string type; rev();//选择题目类型 type = SafeRead::readNum(1, "1"); sendInf(type);//传入题目类型 if (type == "4") { break; } if (type != "1" && type != "2" && type != "3") { rev();//无该类型的提醒 sendInf("");//保证程序正常运行 } rev(); sendInf(SafeRead::readText(1024, "未输入"));//传入题目类型 while (true) { rev();//请输入分值的提醒 std::string inf = SafeRead::readNum(4, "-1"); sendInf(inf);//传递分值 if (inf.c_str()[0] == '-' || inf == "0") { rev();//分值大于0提醒 sendInf(""); continue; } break; } if (type == "1") { rev();//请输入答案选项提醒 sendInf(SafeRead::readString(10, "0"));//获得答案 } else { rev(); sendInf(SafeRead::readText(1024, "未输入"));//获得答案 } rev();//接收回车 sendInf("");//保证程序正常运行 } } void signUp() { std::string res = receiveInf();//读取res sendInf("");//保证程序正常运行 if (res == "true") { rev();//接收考试科目提示 sendInf("");//保证程序正常运行 rev();//接收考试科目及时间 sendInf("");//保证程序正常运行 rev();//报名序号提醒 sendInf(SafeRead::readNum(2, "-1")); std::string low = receiveInf();//接收序号是否正确信息 sendInf("");//保证程序正常运行 if (low == "true") { rev();//没有考试提醒 sendInf("");//保证程序正常运行 } else { low = receiveInf();//接收row sendInf("");//保证程序正常运行 if (low == "true") { rev();//接收考试已报名提醒 sendInf("");//保证程序正常运行 return; } rev();//接收是否报名成功提醒 sendInf("");//保证程序正常运行 } } } void beginTest() { std::string row = receiveInf();//接收row sendInf("");//保证程序正常运行 if (row == "false") { rev();//接收未报名考试的提醒 sendInf("");//保证程序正常运行 } else { rev();//当前报名考试列表的提醒 sendInf("");//保证程序正常运行 rev();//接收已报名的考试列表 sendInf("");//保证程序正常运行 rev();//获取考试序号提醒 std::string ins = SafeRead::readNum(5, "-1"); sendInf(ins); std::string num = receiveInf();//接收考试数量 sendInf("");//保证程序正常运行 if (strToLf(ins) < 1 || strToLf(ins) > strToLf(num)) { rev();//没有该选项提醒 sendInf("");//保证程序正常运行 } else { std::string have = receiveInf();//接收试卷情况 sendInf("");//保证程序正常运行 if (have == "false") { rev(); sendInf("");//保证程序正常运行 } else { std::string number = receiveInf();//接收试题数量 sendInf("");//保证程序正常运行 for (int i = 0; i < strToLf(number); i++) { rev();//收到一个试题 sendInf("");//保证程序正常运行 std::string type = receiveInf();//接收试题类型 sendInf("");//保证程序正常运行 if (type == "1") { rev();//请输入选项提醒 sendInf(SafeRead::readString(15, "未输入")); } else if (type == "2") { rev(); sendInf(SafeRead::readText(500, "未输入")); } else { rev(); sendInf(SafeRead::readText(1024, "未输入")); } } rev();//正在记录成绩提醒 sendInf("");//保证程序正常运行 rev();//考试成绩判断 sendInf("");//保证程序正常运行 rev();//获得考试判断 sendInf("");//保证程序正常运行 } } } } //查看成绩 void checkResult() { rev();//接收参加的考试列表 sendInf("");//保证程序正常运行 rev();//接收成绩 sendInf("");//保证程序正常运行 } //修改题目 void modifySubject() { rev(); sendInf(SafeRead::readString(50,"未输入"));//请输入要修改试题的考试名称 std::string flags = receiveInf();//接收flags sendInf("");//保证程序正常运行 if (flags == "false") { rev(); sendInf("");//保证程序正常运行 } else { rev();//当前试卷如下提醒 sendInf("");//保证程序正常运行 rev();//接收试卷 sendInf("");//保证程序正常运行 rev(); sendInf(SafeRead::readNum(1, "1"));//请输入要修改的题目编号 rev();//请重新输入题目 sendInf("");//保证程序正常运行 while (true) { rev(); std::string type = SafeRead::readNum(1, "1"); sendInf(type);//请输入题目类型 if (type != "1" && type != "2" && type != "3") { rev(); sendInf("");//保证程序正常运行 continue; } rev(); sendInf(SafeRead::readText(1024, "未输入")); while (true) { rev(); std::string scores = SafeRead::readNum(4, "-1"); sendInf(scores); if (scores.c_str()[0] == '-' || scores == "0") { rev(); sendInf("");//保证程序正常运行 continue; } break; } if (type == "1") { rev(); sendInf(SafeRead::readString(1, "0")); } else { rev(); sendInf(SafeRead::readText(1024, "未输入")); } rev(); sendInf("");//保证程序正常运行 break; } rev();//修改成功报告 sendInf("");//保证程序正常运行 } } //删除题目 void deleteSubject() { rev(); sendInf(SafeRead::readString(50, "未输入"));//请输入要删除试题的考试名称 std::string flags = receiveInf();//接收flags sendInf("");//保证程序正常运行 if (flags == "false") { rev(); sendInf("");//保证程序正常运行 } else { rev();//当前试卷如下提醒 sendInf("");//保证程序正常运行 rev();//接收试卷 sendInf("");//保证程序正常运行 rev(); sendInf(SafeRead::readNum(1, "1"));//请输入要删除的题目编号 std::cout << "删除成功nn"; } } //修改用户 void modifyUser() { rev(); std::string order = SafeRead::readNum(1, "1"); sendInf(order);//送出身份选择 if (order == "1") { order = "teacher"; } else { order = "student"; } rev(); sendInf(SafeRead::readString(15, "未输入"));//送出要修改的账号 std::string row = receiveInf();//接收row sendInf("");//保证程序正常运行 if (row == "false") { rev(); sendInf("");//保证程序正常运行 } else { rev(); sendInf("");//保证程序正常运行 rev();//接收当前用户信息 sendInf("");//保证程序正常运行 rev();//接收当前开始修改提示信息 sendInf("");//保证程序正常运行 std::string oldInf; oldInf = receiveInf();//接收老姓名 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readString(20, oldInf));//送出新姓名 oldInf = receiveInf();//接收老专业 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readString(20, oldInf));//送出新专业 if (order == "student") { oldInf = receiveInf();//接收老年级 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readNum(1, oldInf));//送出新年级 oldInf = receiveInf();//接收老班级 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readNum(1, oldInf));//送出新班级 } oldInf = receiveInf();//接收老电话 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readString(11, oldInf));//送出新电话 oldInf = receiveInf();//接收老账号 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readString(20, oldInf));//送出新账号 oldInf = receiveInf();//接收老密码 sendInf("");//保证程序正常运行 rev();//接收提示信息 sendInf(SafeRead::readString(15, oldInf));//送出新密码 rev(); sendInf("");//保证程序正常运行 } } //删除用户 void deleteUser() { rev(); std::string order = SafeRead::readNum(1, "1"); sendInf(order);//送出身份选择 if (order == "1") { order = "teacher"; } else { order = "student"; } rev(); sendInf(SafeRead::readString(15, "未输入"));//送出要删除的账号 std::string row = receiveInf();//接收row sendInf("");//保证程序正常运行 if (row == "false") { rev(); sendInf("");//保证程序正常运行 } else { rev(); sendInf("");//保证程序正常运行 rev();//接收当前用户信息 sendInf("");//保证程序正常运行 rev();//接收是否删除的选择 std::string inf = SafeRead::readNum(1, "2"); sendInf(inf);//送出选择 rev();//接收报告消息 sendInf("");//保证程序正常运行 } }
五、小结
这次实训可谓打了我个措手不及,实训开始前两天才说要用mysql和socket。我只得紧赶慢赶肝了两天学完了mysql基础的语法,而socket则是完全没时间学,,后面完成通信时也是吃了非常大的亏,以至于压到最后时刻才勉强完成,还有很多预期的功能没有做,最后几个做完的功能也有些暴力开发的意思,没有考虑代码精简的问题,容错也不到位。
最后还是那句:如果有bug,请一定一定告诉我!感谢!!!