首先,要完成通信至少要建2个工程,分别为服务端与客户端,这两个工程的环境配置与头文件添加都要按以下步骤进行

一、环境配置

先说mysql环境配置。

右键项目名称,找到属性。

配置属性->调试->环境:将mysql\mysql server \bin 的路径复制,写PATH=路径

其中,如果没有自己定义,那么mysql文件夹一般在C:\program Fiels中。

而后,仍然在属性栏中的C/C++中选择常规,将mysql server 中的include文件夹的路径编辑进附加包含目录中去。别忘了加英文的分号:

接着选择链接器,如下图将lib文件夹的路径编辑进去:

接着选择链接器的输入,点击附加依赖项,选择右边的小箭头,编辑,然后输入: libmysql.lib,选择确定:

然后为代码添加头文件。编译后如果报错,则进行以下操作:

进入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数据类型:整数类型字节有符号取值范围无符号取值范围TINYINT1-128~1270~255SMALLINT2-32768~327670~65535MEDIUMINT3-8388608~83886070~16777215INT4-2147483648~21474836470~4294967295BIGINT8-9223372036854775808~92233720368547758070~18446744073709551615整数类型的可选属性有三个:(M)表示最低显示宽度,例如int(5),当数据宽度小于5位时在数字前面需要用字符填满宽度。该项功能要配合”ZEROFILL“使用,否则指定宽度无效。如果设置了显示宽度,不会对插入的数据有影响,还是按照类型的实际宽度保存。从MySQL8.0.17开始,整数数据类型不推荐使用显示宽度属性。UNSIGNED表示无符号类型。使用:INT UNSIGNEDZEROFILL表示0填充。如果某列是ZEROFILL,那么mysql会自动为当前列添加UNSIGNED属性。如果指定了ZEROFILL表示不够M位时,用0在左边填充,超过M位时,只要不超过数据存储范围即可。(M)必须和UNSIGNED ZEROFILL一起使用才有意义,M的值跟int所占多少存储空间没有关系,int(3),int(4)在磁盘上都是占用4个字节。字符串类型字节描述及存储需求CHAR(M) MM为0~255之间的整数VARCHAR(M) M为0~65536之间的整数TINYBLOB 允许长度0~255字节BLOB 允许长度0~65535字节MEDUIMBLOB 允许长度0~167772150字节LONGBLOB 允许长度0~4294967295TINYTEXT 允许长度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是复选。浮点类型占用空间精度精确性FLOAT4单精度精确到小数点后7位小数DOUBLE8双精度精确到小数点后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,NUMERICM+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)M1<=Mor 或 ||_表示一个任意字符大于等于 >=not 或 !小于 <小于等于 <=不等于 != 或 范围 BETWEEN...AND...左小于右列表多选一 IN(...)范围查询空值查询in表示在一个非连续的范围内is nullnot 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必须小于等于值2select 字段列表 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 = 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 * fromemployee 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到长度nrpad(str,n,pad) 右填充,用字符串pad填充str到长度ntrim(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,否则返回fifnull(value1, value2) 如果value1不为空,返回value1,否则返回value2case 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'); 返回defaultselectid,name,(case when math >= 85 then '优秀' when math >= 60 then '及格' else '不及格' end) '数学';from score;selectname,(case workaddress when '北京' then '一线' when '上海' then '一线' else '二线' end) as '工作地址'from employee;约束关键字约束名效果not null非空约束限制该字段数据不能为nullunique唯一约束保证该字段所有数据都唯一,不重复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  #include #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++中的TCPWSAData 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:ton:net 网络的意思l:unsigned longINADDR_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 接收到数据大小send():将我们的数据复制黏贴进系统的协议发送缓冲区,计算机伺机发送出去参数1:标识已连接套接字的描述符。参数2:指向包含要传输的数据的缓冲区的指针。参数3:buf参数指向的缓冲区中数据的长度(以字节为单位)。参数4:一组标志,指定进行呼叫的方式。 通过将按位或运算符与以下任何值一起使用来构造此参数。返回值:成功返回写入的字节数;执行失败,返回SOCKET_ERRORclosesocket():关闭一个套接口

三、头文件添加

下面是代码。代码分为三部分 服务端,客户端,还有一个我自己定义的stdafx头文件。这个头文件是vs库自带的。我的出于某些原因没有。当然,如果你有的话,将stdafx头文件放在最上方,下方添加以下头文件:

#include  #include  #include #pragma comment(lib,"libmysql.lib")#pragma comment(lib,"wsock32.lib")#pragma comment(lib,"ws2_32.lib")#include #include#include#include#include #include #include #include #include

如果不知道头文件如何创建:

刚创好的头文件会自带一行#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)#defineDLLIMPORT __declspec(dllimport)#include  #include  #include #pragma comment(lib,"libmysql.lib")#pragma comment(lib,"wsock32.lib")#pragma comment(lib,"ws2_32.lib")#include #include#include#include#include #include #include #include #include// TODO: reference additional headers your program requires herevoid 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 += '\0';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 < length) {std::cout << "\n\t长度超过" << length <> 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  length) {std::cout << "\n\t信息长度超过" << length < 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 <> 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]  '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 createRandList(int left, int right) {int length = right - left + 1;std::default_random_engine start;std::uniform_int_distribution getRand(left, right);start.seed(time(0));std::unordered_set list;while (list.size() < length) {list.insert(getRand(start));}std::vector 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);//初始化localMysqlif (!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 = "Field\tType\tNull\tKey\tDefault\tExtra\n";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::vectorfieldList, std::vector<std::vector> 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::vectorfieldList, std::vectordataList, 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 fieldList, std::string tableName, std::string condition, std::vector<std::pair> 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 fieldList, std::string tableName, std::string condition, std::string gropField, std::string gropCondition, std::vector<std::pair> sortList, std::pair 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::vectordataList;sendInf("请输入考试科目: ");dataList.push_back(receiveInf());//string 50sendInf("请输入考试分值: ");dataList.push_back(receiveInf());//int 5sendInf("请输入考试时间表,可换行。结束时另起一行输入 ~~~ 结束:\n");dataList.push_back(receiveInf());//text 500bool res = MysqlOperation::addData("subject", std::vector{"subName", "fullScore", "time"}, std::vector<std::vector>{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 50std::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 2if (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> testList;while (true) {std::vector testEdit;sendInf("请选择题目类型,输入4退出添加题目: 1 选择题 2填空题 3 大题: ");std::string type = receiveInf();//num 1 de 0if (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 -1if (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 0std::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 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 testEdit;while (true) {sendInf("请选择题目类型: 1 选择题 2填空题 3 大题: ");std::string type = receiveInf();//num 1 de 0if (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 -1if (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 0std::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 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 subjectList;std::vector 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] + "\n\n";}sendInf(low);receiveInf();//保证程序正常运行sendInf("请输入要报名的序号: ");std::string serial = receiveInf();//num 2 de -1int 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 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> studentList;studentList.push_back(oneStudent);std::vector fieldList = { "studentName", "studentMajor","studentGrade","studentClass", "studentAccont" };if (MysqlOperation::addData(subjectList[se - 1], fieldList, studentList)) {std::vector fieldList2 = { "id", "accont","subjectName" };std::vector data = { id,userInf[1],subjectList[se - 1] };std::vector< std::vector> 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 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::vectornameList;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 -1sendInf(std::to_string(nameList.size()));//送出考试数量receiveInf();//保证程序正常运行if (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 scoreList(4);std::string oper = "select `id`, `type`, `topic`, `score`, `answer` from `" + nameList[sea - 1] + "test`";std::vector<std::vector> testPaper;MysqlOperation::useQuery(mysql, oper);result = mysql_store_result(mysql);row = mysql_fetch_row(result);while (row) {std::vector 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 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 fieldList = { nameList[sea - 1] + "Score" };std::vector sc = { lfToStr(scoreList[3]) };MysqlOperation::modifyData("student", fieldList, sc, " accont = '" + userInf[1] + "'");MysqlOperation::addData(nameList[sea - 1], std::vector{"studentName", "studentMajor", "studentGrade", "studentClass", "studentAccont", "score"}, std::vector<std::vector>{std::vector{userInf[2], userInf[3], userInf[4], userInf[5], userInf[1], lfToStr(scoreList[0] + scoreList[1] + scoreList[2])}});sendInf("记录完成!\n\n");receiveInf();//保证程序正常运行std::string lowss = "\n考试已完成, 题目已由系统批改,其中:\n选择题得分: " + std::to_string(scoreList[0]) + "\n"+ "填空题得分: " + std::to_string(scoreList[1]) + "\n"+ "大题得分: " + std::to_string(scoreList[2]) + "\n\n"+ "总分: " + std::to_string(scoreList[3]) + "\n\n"+ "填空题,大题部分由于本系统的无能或许会出现误判,请\n等待老师手动重批,以上成绩仅供参考\n";sendInf(lowss);receiveInf();//保证程序正常运行}}}}}//查看成绩static void checkResult(std::vector userInf) {MYSQL* mysql = &localMysql;MYSQL_RES* result;MYSQL_ROW row;std::string oper;std::vector 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 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 = 7) {ans += "\t";}}}ans += "\n";row = mysql_fetch_row(result);}sendInf(ans);receiveInf();//保证程序正常运行mysql_free_result(result);}}};class User {public://登录static std::vector signIn() {MYSQL* mysql;MYSQL_RES* result;MYSQL_ROW password;std::vector re;while (true) {std::string sendOut = R"(登录:请选择身份:1 教师2 学生请输入序号:)";sendInf(sendOut);//送出身份选择std::string order = receiveInf();//获得身份re.push_back(order);//储存身份std::vector inf;sendInf("server: 请输入账号:");inf.push_back(receiveInf());//获得账号 string20sendInf("server: 请输入密码:");inf.push_back(receiveInf());//获得密码 string 15mysql = &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 inf;sendInf("server: 请输入姓名:");inf.push_back(receiveInf());//获得姓名,string 20sendInf("server: 请输入专业:");inf.push_back(receiveInf());//获得专业,string 20if (order == "2") {sendInf("server: 请输入年级:");inf.push_back(receiveInf());//获得年级,int 2sendInf("server: 请输入班级:");inf.push_back(receiveInf());//获得班级 int 2}sendInf("server: 请输入电话:");inf.push_back(receiveInf());//string 11sendInf("server: 请输入账号:");inf.push_back(receiveInf());//string 20sendInf("server: 请输入密码:");inf.push_back(receiveInf());//string 15std::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 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> 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 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 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 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 << "初始化完成!" <v_<| |___________________________________|)");return receiveInf();//服务端是否要求主机关机}//登录界面static std::vector signInVisual() {std::vector 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);//有IPif (::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 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 < length) {std::cout << "\n\t长度超过" << length <> 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  length) {std::cout << "\n\t信息长度超过" << length < 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]  '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");//服务端IPsvrAddr.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(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 += '\0';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, "未输入"));//送出账号 最长20rev();//保证正常运行sendInf(SafeRead::readString(15, "未输入"));//送出密码 最长15std::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();//接收ressendInf("");//保证程序正常运行if (low == "true") {rev();//接收设置成功的消息sendInf("");//保证程序正常运行}}void createTest() {rev();sendInf(SafeRead::readString(50, "未输入"));//传递考试科目std::string low = receiveInf();//接收ressendInf("");//保证程序正常运行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();//读取ressendInf("");//保证程序正常运行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();//接收rowsendInf("");//保证程序正常运行if (low == "true") {rev();//接收考试已报名提醒sendInf("");//保证程序正常运行return;}rev();//接收是否报名成功提醒sendInf("");//保证程序正常运行}}}void beginTest() {std::string row = receiveInf();//接收rowsendInf("");//保证程序正常运行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)  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();//接收flagssendInf("");//保证程序正常运行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();//接收flagssendInf("");//保证程序正常运行if (flags == "false") {rev();sendInf("");//保证程序正常运行}else {rev();//当前试卷如下提醒sendInf("");//保证程序正常运行rev();//接收试卷sendInf("");//保证程序正常运行rev();sendInf(SafeRead::readNum(1, "1"));//请输入要删除的题目编号std::cout << "删除成功\n\n";}}//修改用户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();//接收rowsendInf("");//保证程序正常运行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();//接收rowsendInf("");//保证程序正常运行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,请一定一定告诉我!感谢!!!