团队介绍
单位名:怀化学院计算机科学与工程学院。
课程名称:高级程序语言设计。
班级 小组序号:1901班 第十一小组。
团队名称:“主C显”小组。
课程设计题目:《学生限时答题评测系统》
课程设计题目基本要求介绍
功能模块一:登录
1,限制账号要以10位学号+姓名的方式登录,否则重新登录
2,登录成功后将基本信息(如账户,IP地址等)发送给服务器
3,登录成功后窗口标题应修改为该账户名
功能模块二:预备工作
1,对答题者输入的用户名进行整理,可以允许答题者在输入学号前输入空格和回车,开始输入学号后可以允许输入空格。(程序不会被开始输入的回车及空格影响,并且会自动消除开始输入后的空格)
2,进行答题时间的限制,练习版可以进行答题者自我规定。
3, 告知答题者答题时间限制和总题数限制,
在答题者按任意键确认并开始答题。
(进行一次暂停)
4, 进行倒计时,规定倒计时以秒为单位没过1秒提示一次。(进行一个延时输出的设置)
功能模块三:测试工作
1,题库的输入和题目的输出
题库由出题者输入,按"...题目...","...答案...","...题目..."......;组成(注意" " ,要用英文的);
从题库中随机抽出一道题,抽题随机不重复。
2,答案的处理
排除大小写的干扰。(将输入的答案中的英文字母全部小写化)
允许答题者在开始输入答案前可以输入回车和空格,并且在输入答案后可以允许在途中输入空格。(答案中的空格可以被消除,答案前的回车和空格不会影响答案)
3,答案的判断
将答题者的答案与正确答案做对比。
4,答题后的反馈
如果答题者回答正确,提示答案正确。(将答题者的正确答题数+1)
如果回答错误,提示答案错误,并告知正确答案。
答题者总答题数+1
告知答题者本题用时和总用时,并提示至本题为止共回答多少题,回答正确多少题。
5,进行模块三1-4的循环(在时间达到限定时间或总答题数达到总题数时进行循环停止)
结束后会提示答题者总答题数,总正确题数,正确率,分数,所总时间。(定义评分标准)
模块四:进行成绩分类
根据答题者的得分显示一个对应的表格,进行等级划定,及语言提示。(设置等级划定的规划,并设置对应的语言提示,不同等级表格颜色要不同)
程序不会因为答题结束而关闭。(进行一个暂停设置)
模块五:客户端
可以自动建立一个文档将屏幕上的所以内容保存在文档中。(文档要txt文档)
将关键信息传输给服务端。(关键信息指答题者信息,总答题数,正确题数,答题正确率,总用时,总分数)
模块六:服务器
可以接受客户端传输的内容,并进行保存,且可以不断接收客户端的连接,并且每个客户端发送的信息都可以保存在一起。
流程图
核心功能讲解
1,便捷输入题库的功能
void comprehensive(char subject[TM][100],char answer[TM][100])//便捷输入题库(可按一题,一答案,的方式输入)
{
int i , j ;
j = 0 ;
for(i = 0 ; i < TM * 2 ;i += 2 )
{
strcpy ( subject[j] , subjct_and_answer[i]);
strcpy ( answer[j] , subjct_and_answer[i + 1]);
j += 1;
}
}
便捷输入题库的功能如果加入文件导入二维数组可以进一步优化,此功能只需要时间便可以完成
2,排除回车空格对答案输入的影响
void eliminate(char * l)
{
int j ;
char g[100] , h[100];
for( j = 0 ; j < 100 ; j++ )
{
scanf( "%c" ,&g[j]);
if( g[j] != ' ' && g[j] > 13)
{
g[0] = g [j];
g[1] = '\0';
break ;
}
}
gets(h);
fun (h);
strcpy( l , strcat ( g , h ) );
}
**3,排除空格**
void fun(char *a)
{
int i=0, j=0;
for (i = 0; i < strlen(a); i++)
{
if (a[i] != ' ')
{
a[j++] = a[i];
}
else if(a[i]==' ')
{
continue;
}
}
a[j] = '\0';
}
在数组最后面加上字符串结束符’\0’
**3,**从文件中读入题目与答案,并且设置难易题目的比例
void ltemBankReading(int sumY ,int sumN )
struct tiku
{
char timu[50] ;
char daan[20] ;
};
int i ,j ;
FILE * fp ;
struct tiku arrayY[sumY] ,arrayN[sumN];
if( ( fp = fopen( "tikuY.txt","r" ) ) == NULL )//在stdio.h中已经定义NULL为0;
{
printf("cannot open this file\n");
exit(0);//终止程序
}
for( i = 0 ; i < sumY ; i++ )
{
fscanf(fp,"%s",arraY[i].timu);
fscanf(fp,"%s",arraY[i].daan);
}
fclose(fp);//关闭成功返回0,否则返回EOF(-1)
if( ( fp = fopen( "tikuN.txt","r" ) ) == NULL )//在stdio.h中已经定义NULL为0;
{
printf("cannot open this file\n");
exit(0);//终止程序
}
for( i = 0 ; i < sumN ; i++ )
{
fscanf(fp,"%s",arraN[i].timu);
fscanf(fp,"%s",arraN[i].daan);
}
fclose(fp);//关闭成功返回0,否则返回EOF(-1)
}
(2020.02.02对此进行补充)
4,将所要输出的文字输出并保存在文档
void showfile_and_savefile(FILE *fp,int c,const char *format,...)
{
va_list args;
switch(c)
{
case 1:SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN);
break;
case 2:SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED);
break;
case 3:SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED);
break;
case 4:SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_GREEN|FOREGROUND_RED);
break;
}
va_start(args,format);
printf(format,args);
vfprintf(fp,format,args);
va_end(args);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}
知识引用于 https://blog.csdn.net/bribo/article/details/12973519
https://blog.csdn.net/u012349696/article/details/42398107
5,规定要10位学号加名字
int islogin(char*a)
{
int i,count=0;
for( i = 0 ; i <= 9 ; i++)
{
if( a[i] <= '9' && a[i] >= '0')
{
count++;
}
}
if(count == 10)
{
if( a[0]=='1' && a[1] >= '6'
&& a[1] <= '9' && a[2] == '0'
&& a[3] == '0' && a[4] == '1'
&& a[5] == '3' && a[6] == '0'
&& a[10] != '\0')
{
return 0;
}
else
{
return 1;
}
}
else
{
return 1;
}
}
6,服务器
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib , "ws2_32.lib")
#define DEFAULT_BUFFER 4096 /*缓冲区大小*/
#define PORT 0
#define IP 1
char getparameter[2][64];
//FILE * fpRead;
FILE * fp;
//FILE * fp = fopen( "答题信息汇总.txt" , "w" );
/*与客户机通信的线程函数*/
DWORD WINAPI ClientThread(LPVOID lpParam)
{
FILE * fp = fopen( "答题信息汇总.txt" , "a" );
SOCKET sock = (SOCKET)lpParam;
char Buffer[DEFAULT_BUFFER];
int ret , nLeft , idx;
while (1) {
/*接收来自客户机的消息*/
ret = recv(sock , Buffer , DEFAULT_BUFFER , 0);
if (ret == 0)
break;
else if (ret == SOCKET_ERROR) {
printf("recv() 失败: %d\n" , WSAGetLastError());
break;
}
Buffer[ret] = '\0';
printf("已接收来自%s字符: %s\n" , getparameter[IP] ,Buffer); //打印接收到的消息
fprintf( fp , "已接收来自%s字符: %s\n" , getparameter[IP] ,Buffer);
fclose(fp);
nLeft = ret;
idx = 0;
while (nLeft > 0) {
/*向客户机发送回应消息*/
ret = send(sock , &Buffer[idx] , nLeft , 0);
if (ret == 0)
break;
else if (ret == SOCKET_ERROR) {
printf("send() 失败: %d\n" , WSAGetLastError());
break;
}
nLeft -= ret;
idx += ret;
}
}
return 0;
}
int main( )
{
FILE * fp = fopen( "答题信息汇总.txt" , "w" );
WSADATA wsd;
HANDLE hThread;
DWORD dwThread;
SOCKET sListen , sClient;
int AddrSize;
unsigned short port;
struct sockaddr_in local , client;
printf("请输入服务器端口号:");
gets(getparameter[PORT]);
/*加载Winsock DLL*/
if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
printf("WinSock 初始化失败!\n");
return 1;
}
/*创建Socket*/
sListen = socket(AF_INET , SOCK_STREAM , IPPROTO_IP);
if (sListen == SOCKET_ERROR) {
printf("socket() 失败: %d\n" , WSAGetLastError());
return 1;
}
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
port = atoi(getparameter[PORT]); //获取端口值
local.sin_port = htons(port);
/*绑定Socket*/
if (bind(sListen ,
(struct sockaddr*)&local ,
sizeof(local)) == SOCKET_ERROR) {
printf("bind() 失败: %d\n" , WSAGetLastError());
return 1;
}
/*打开监听*/
listen(sListen , 8);
/*在端口进行监听,一旦有客户机发起连接请示
就建立与客户机进行通信的线程*/
while (1) {
AddrSize = sizeof(client);
/*监听是否有连接请求*/
sClient = accept(sListen ,
(struct sockaddr*)&client ,
&AddrSize);
if (sClient == INVALID_SOCKET) {
printf("accept() 失败: %d\n" , WSAGetLastError());
break;
}
strcpy(getparameter[IP],inet_ntoa(client.sin_addr));
printf("接受客户端连接: %s:%d\n" ,
inet_ntoa(client.sin_addr) ,
ntohs(client.sin_port));
//创建一个线程去处理
hThread = CreateThread(NULL , 0 , ClientThread ,
(LPVOID)sClient , 0 , &dwThread);
if (hThread == NULL) {
printf("CreateThread() 失败: %d\n" , GetLastError());
break;
}
//处理完后关闭
CloseHandle(hThread);
}
closesocket(sListen);
WSACleanup(); //用完了要清理
return 0;
}
7,倒计时程序
void timeback(int r)
{
while(r>0)
{
printf( "************************倒计时%d*****************************\n" , r );
Sleep(1000);
r--;
}
}
本设置适应本次项目需要
项目未完成的功能
1,未完成从文件中读入题库(只是时间问题)
2,未完成连接互网络的内容(暂时尚未掌握足够能力)
版本更新日志
测验小程序PATCH修正说明:
V服务器完美版(2019-11-24)
1,可以接受客户端传送来的信息并保存。
V2.0.0(2019-11-23)
客户端版成功,可以自动将答题信息存档保存。
V1.2.0(2019-11-21):
1,进行函数的优化,将部分功能函数化。
2,解决输入学号时在输入前输入回车和输入过程中有空格的问题。
V1.1.0(2019-11-19):
1,程序自动生成一个txt文档,并实现将所有屏幕上的内容保存在txt文档中。
2,当答题者输入完成学号和姓名后,窗口自动改为学号加姓名。
V1.0.1(2019-11-19) :
1, 修改和完善排除空格回车干扰的功能。(欧阳有澳)
2,实现最终的绘制表格有颜色区分。(欧阳有澳)
V1.0.0(2019-11-17):
1,提示答题者输入学号和姓名。在这里插入代码片
2,如果输入学号错误或者有空格,提示输入错误,重新输入。(唐新坤)
3,支持答题时大小写字母均可正确。
4,答案不受空格和回车影响。(段文杰)!(经测试有错误)
5,回答错误和回答正确会有不同样色的字符提示。(欧阳有澳)
6,回答完一题会告知本题用时,和总用时,及答题个数和正确题数。
7,可以进行5秒倒计时提示。(欧阳有澳)
8,可以进行答题时间的限制。(段文杰)
9,可以打出表格对成绩进行分类和评价,并且字体颜色不同。(欧阳有澳)(1.0.0是未实现)
10,可以告知答题者正确率。
相关文档地址
- https://pan.baidu.com/s/1HySs1Kv5TTzTgCOV4dfORg
每位成员的过程心得
组长 欧阳有澳 个人心得:
这是本人第一次进行项目领导,本人感受到领导的重要性,团队的带领需要领导者考虑到每个人的性格和能力来分配任务,
还得根据工作量和限定的项目时间时间来合理分任务,(此次本人因个人原因导致程序最后的进程拖延了),本人还意识到了团
队管理对于一个团队的重要性;
编程收获:
本次项目编程让我之前学的许多知识得到巩固和加深,还然我学到了怎样面向百度编程,还培养了自己的学习能力;并且学到了
于他人讨论遇到的各种问题;本人还认识到程序优化的重要性,尽量封装自定义函数是主函数简化。
组员 段文杰 个人心得:
我在这一次的课程设计,也是第一次课程设计中发现了许多问题,也收获了许多。
首先,一个大的课程设计在规定时间内,并不是一个人可以完成的,而是由多个人一同努力才
可以做到,这就要求,小组内每个组员有良好的沟通和配合以及分工,这是对组员的要求,更是对组长的要求。
然后在一个小组内,有时组员之间可能在不同方面有着不同的方法,可以有效的取长补短。
然后说一下,我所遇到的问题:
第一,对于一些任务的时间安排有些冲突,导致自己的时间过于紧凑。
第二,在函数的难易程度上的判断不精确,没能很好的完成所有代码。
对于这一次的编程,整体来说,我还是对我,以及我们小组的表现很满意,如果可能,
希望在下一次的课程设计中在一起努力
组员 唐新坤 个人心得:
通过这次团队合作,我深刻的意识到了团队的重要性,当我遇到难题时,组长和另一个组员都给我提供了很多支持,这才使我顺利的完成了任务,当组长或其他组员遇到困难时我也会从旁协助,尽力完成我们共同的任务,能完成这个任务是大家一起努力的结果。