(实训)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,请一定一定告诉我!感谢!!!