c入门第二十三篇: 学生成绩管理系统优化(支持远程操作)

前言

师弟高兴的说道:“师兄,你猜我今天上课看见谁了?”
我:“谁呢?”
师弟:“程夏,没想到,她竟然来旁听我们计算机系的课程了。虽然我从前门进去的,但是我还是一眼就看见了坐在后面的她。”
我:“有意思,你没过去打个招呼?”
师弟:“我正要挨过去坐着,被占位的室友拉住了,就不好意思了。还好第一节课间休息的时候,我果断溜了过去。”
师弟开始回想当时的场景,嘴角先是上扬,接着又下扬。当时她在忙着看书,等我在她旁边坐下,稍微撇过头看她看什么书的时候,她才发现的我。她说:‘上课都不积极,踩着点来上课。’我先是惊讶了,然后不好意思地说:‘程老师批评的对。’接下来竟是一段沉默。打破沉默的还是她,她说道:‘你现在的学生成绩管理系统只支持运行时候,在运行的程序终端进行输入。你能够支持一下,我在我的电脑上,也能连上你的系统设置么?’我听得有点懵,我从来没想到还能这样实现。我原以为我的系统已经可以了。她见我茫然,就说:‘可以好好想想。期待你更新的版本。’说完她就自顾看书去了。我则一整节课都在思考这个问题。
师弟:“师兄,她说要实现在她电脑上,也能连上我的系统,这个有经验可以分享一下么?”
我:“这个倒是不复杂,就是c/s架构,客户端和服务端分离。可以通过c语言中的网络套接字实现。”

背景

在C语言中,可以使用网络套接字(Socket)来实现基于网络的进程间通信。可以先看下面TCP通信的服务端和客户端代码。主要实现的功能是客户端发送一个“Hello message sent”,服务端回复一个“Hello from server”。
互相发送hello问候

服务端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>#define PORT 8080int main() {int server_fd, conn_socket;struct sockaddr_in address;int opt = 1;int addrlen = sizeof(address);char buffer[1024] = {0};char *hello = "Hello from server";// Creating socket file descriptorif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}// Forcefully attaching socket to the port 8080if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// Bind the socket to the addressif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// Listen for connectionsif (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}// Accept a connectionif ((conn_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// Read data from the socketread(conn_socket, buffer, 1024);printf("Message from client: %s\n", buffer);// Send data to the clientsend(conn_socket, hello, strlen(hello), 0);printf("Hello message sent\n");close(conn_socket);close(server_fd);return 0;
}

客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>#define PORT 8080int main() {int sock = 0;struct sockaddr_in serv_addr;char *hello = "Hello from client";char buffer[1024] = {0};// Create a socketif ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {printf("\n Socket creation error \n");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// Convert IPv4 and IPv6 addresses from text to binary formif(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {printf("\nInvalid address/ Address not supported \n");return -1;}// Connect to the serverif (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {printf("\nConnection Failed \n");return -1;}// Send data to the serversend(sock, hello, strlen(hello), 0);printf("Hello message sent\n");// Read data from the serverread(sock, buffer, 1024);printf("Message from server: %s\n", buffer);close(sock);return 0;
}

整个编程实现的过程可以总结如下:
客户端服务端TCP通信流程

学生成绩管理系统的实现

这里主要是考虑将上文中的客户端和服务端代码如何在学生系统中实现。其中的关键就是socket_server_init,实现了服务端的监听,以及数据的处理。

int socket_server_init()
{int ret;int server_fd, conn_fd;int opt = 1;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[BUF_SIZE] = {0};// 创建 TCP socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed!");exit(EXIT_FAILURE);}if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt!");exit(EXIT_FAILURE);}#define PORT 8080address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// Bind the socket to the addressif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed!");exit(EXIT_FAILURE);}// Listen for connectionsif (listen(server_fd, 3) < 0) {perror("listen!");exit(EXIT_FAILURE);}while (1) {// Accept a connectionif ((conn_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}while (1) {// Send data to the clientret = send(conn_fd, welcome_info, strlen(welcome_info), 0);if (ret == -1) {perror("sent failed!\n");break;}// Read data from the socketret = read(conn_fd, buffer, BUF_SIZE);if (ret == -1) {perror("read failed!\n");break;}printf("recv: %s\n", buffer);ret = server_process_to_client(conn_fd, buffer);if (ret == 1) {break;}}close(conn_fd);}close(server_fd);return 0;
}

完整服务端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for access() function
#include <sys/socket.h>
#include <netinet/in.h>#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"
#define TRUE 1
#define FALSE 0
#define BUF_SIZE 1024char *welcome_info = "\nWelcome to Student Score Management System\n"\"0. Exit\n"\"1. Add Student\n"\"2. Display All Students\n"\"3. Find Student by ID\n"\"4. Find Student by Name\n"\"5. Add Score\n"\"6. Display Average Score\n"\"7. Display by Score sort\n"\"Enter your choice: ";typedef struct {int id; // 学号char name[MAX_NAME_LEN]; // 姓名float score; // 成绩
} Student;int student_count = 0; // 学生数量Student *students; // 学生数组指针
int g_max_student = MAX_STUDENTS;Student *stu_sys_init(int num)
{Student *stu_sys;stu_sys = malloc(num * sizeof(Student));if (stu_sys == NULL) {printf("student system malloc failed!\n");}return stu_sys;
}int write_student_info(Student *s)
{FILE *fp = fopen(STUDENT_SYSTEM, "a");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);fclose(fp);return 0;
}int check_if_student_exsit(int id)
{int i;for(i = 0; i < student_count; i++) {if(students[i].id == id) {return 1;}}return 0;
}void update_student_info(Student s, int need_write)
{Student *stu_reinit;int old_max_student;if(student_count >= g_max_student) {old_max_student = g_max_student;g_max_student = g_max_student << 1;stu_reinit = stu_sys_init(g_max_student);if (stu_reinit == NULL) {printf("Database is full!\n");return;}memcpy(stu_reinit, students, old_max_student * sizeof(Student));free(students);students = stu_reinit;}if (!check_if_student_exsit(s.id)) {students[student_count++] = s;if (need_write) {printf("Student added successfully, all student: %d!\n", student_count);write_student_info(&s);}} else {printf("student has in db, do nothing!\n");}
}void add_student()
{Student s;printf("Enter student ID: ");scanf("%d", &s.id);printf("Enter student name: ");scanf("%s", s.name);s.score = 0.0; // 初始成绩设置为0update_student_info(s, TRUE);
}void print_title()
{printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}void display_all_students()
{int i;printf("-------- All students info --------\n");if (student_count == 0) {printf("No students!\n");} else {print_title();for(i = 0; i < student_count; i++) {printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);}}printf("--------      End       -----------\n");
}/*** @arr: 有序数组* @l: 待查找区间左端点* @r: 待查找区间右端点* @target: 需要查找的元素*/
int binary_search(Student *s, int l, int r, int target)
{int m;while (l <= r) {// 计算中间位置m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出// 检查x是否存在于中间位置if (s[m].id == target)return m;// 若x大,则忽略左半部分if (s[m].id < target) {l = m + 1;} else {// 若x小,则忽略右半部分r = m - 1;}}// 若未找到元素,返回-1return -1;
}void find_student_by_id()
{int id, ret;printf("Enter student ID to search: ");scanf("%d", &id);ret = binary_search(students, 0, student_count, id);if (ret != -1) {print_title();printf("%-4d %-10s %-.2f\n", students[ret].id, students[ret].name, students[ret].score);return;}printf("Student with ID %d not found!\n", id);
}void find_student_by_name()
{int i, is_find = 0;char name[MAX_NAME_LEN];printf("Enter student name to search: ");scanf("%s", name);for(i = 0; i < student_count; i++) {if(strcmp(students[i].name, name) == 0) {print_title();printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);is_find = 1;}}if (is_find == 0) {printf("Student with name %s not found!\n", name);}
}void add_score()
{int id, i;float score;printf("Enter student ID: ");scanf("%d", &id);printf("Enter student score: ");scanf("%f", &score);for(i = 0; i < student_count; i++) {if(students[i].id == id) {students[i].score = score;printf("Score added successfully!\n");return;}}printf("Student with ID %d not found!\n", id);
}void display_average_score()
{float total = 0.0;int i;for(i = 0; i < student_count; i++) {total += students[i].score;}printf("Average score of all students: %.2f\n", total / student_count);
}int init_student_info()
{if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在return 0;}FILE *fp = fopen(STUDENT_SYSTEM, "r");if (fp == NULL) {printf("fopen student_system failed!\n");return 1;}#define BUF_SIZE 1024char buf[BUF_SIZE];Student s;while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {sscanf(buf, "%d %s %f\n", &s.id, s.name, &s.score);update_student_info(s, FALSE);}fclose(fp);return 0;}void swap(Student *a, Student *b)
{Student tmp = *a;*a = *b;*b = tmp;
}void bubble_sort_by_score(Student *s, int n)
{int i, j;for (i = 0; i < n-1; i++) {for (j = 0; j < n-i-1; j++) { // 最后 i 个已经排序好了, 遍历未排序的部分if (s[j].score < s[j+1].score) {// 如果当前元素大于后面的元素,交换它们swap(&s[j], &s[j+1]);}}}
}int do_process(int choice)
{switch(choice) {case 0:printf("Exiting...\n");break;case 1:add_student();break;case 2:display_all_students();break;case 3:find_student_by_id();break;case 4:find_student_by_name();break;case 5:add_score();break;case 6:display_average_score();break;case 7:bubble_sort_by_score(students, student_count);display_all_students();break;default:printf("Invalid choice!\n");}return 0;
}int do_exit(int fd)
{int ret;char *exit_instruct = "Exit";ret = send(fd, exit_instruct, strlen(exit_instruct), 0);if (ret == -1) {perror("sent failed!\n");return -1;}printf("send: %s\n", exit_instruct);return 0;
}int do_add_student(int fd)
{int ret;char *enter_id_helps = "Enter student ID:";char *name_helps = "Enter student name:";Student s;char buf[BUF_SIZE];ret = send(fd, enter_id_helps, strlen(enter_id_helps), 0);if (ret == -1) {perror("sent failed!\n");return -1;}printf("send: %s\n", enter_id_helps);// Read data from the socketret = read(fd, buf, BUF_SIZE);if (ret == -1) {perror("read failed!\n");return -1;}s.id = atoi(buf);ret = send(fd, name_helps, strlen(name_helps), 0);if (ret == -1) {perror("sent failed!\n");return -1;}// Read data from the socketmemset(buf, 0, BUF_SIZE);ret = read(fd, buf, BUF_SIZE);if (ret == -1) {perror("read failed!\n");return -1;}strcpy(s.name, buf);s.score = 0.0; // 初始成绩设置为0update_student_info(s, TRUE);return 0;
}int server_process_to_client(int fd, char *buffer)
{int choice = atoi(buffer);switch(choice) {case 0:do_exit(fd);return 1;case 1:do_add_student(fd);break;default:printf("Invalid choice!\n");}return 0;
}int socket_server_init()
{int ret;int server_fd, conn_fd;int opt = 1;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[BUF_SIZE] = {0};// 创建 TCP socketif ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed!");exit(EXIT_FAILURE);}if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {perror("setsockopt!");exit(EXIT_FAILURE);}#define PORT 8080address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(PORT);// Bind the socket to the addressif (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed!");exit(EXIT_FAILURE);}// Listen for connectionsif (listen(server_fd, 3) < 0) {perror("listen!");exit(EXIT_FAILURE);}while (1) {// Accept a connectionif ((conn_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}while (1) {// Send data to the clientret = send(conn_fd, welcome_info, strlen(welcome_info), 0);if (ret == -1) {perror("sent failed!\n");break;}// Read data from the socketret = read(conn_fd, buffer, BUF_SIZE);if (ret == -1) {perror("read failed!\n");break;}printf("recv: %s\n", buffer);ret = server_process_to_client(conn_fd, buffer);if (ret == 1) {break;}}close(conn_fd);}close(server_fd);return 0;
}void welcome_sys_menu()
{printf("%s", welcome_info);
}int main()
{int choice;int ret;students = stu_sys_init(MAX_STUDENTS);if (students == NULL) {printf("student system init failed, exit!\n");return -1;}ret = init_student_info();if (ret) {printf("init_student_info failed!\n");return 1;}display_all_students();socket_server_init();#if 0 //通过if 0注释代码do {welcome_sys_menu();scanf("%d", &choice);do_process(choice);} while(choice != 0);
#endifreturn 0;
}

客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>#define PORT 8080
#define BUF_SIZE 1024int main() {int sock = 0;struct sockaddr_in serv_addr;char buffer[BUF_SIZE] = {0};// Create a socketif ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {printf("Socket creation error!\n");return -1;}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(PORT);// Convert IPv4 and IPv6 addresses from text to binary formif(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) { //127.0.0.1需要换成服务器所在地址printf("Invalid address/ Address not supported!\n");return -1;}// Connect to the serverif (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {printf("Connection Failed!\n");return -1;}while (1) {memset(buffer, 0, BUF_SIZE);// Read data from the serverread(sock, buffer, BUF_SIZE);printf("%s", buffer);if (strcmp(buffer, "Exit") == 0) {printf("\nNormal Exit, bye!\n");break;}// Send data to the serverscanf("%s", buffer);send(sock, buffer, strlen(buffer), 0);}close(sock);return 0;
}

在实际应用中127.0.0.1需要换成服务器所在地址。

结尾

在这里只是实现了学生成绩管理系统的添加功能和退出功能,其他功能如显示、查询功能有待进一步实现。你以为这就构造好了一个学生成绩管理系统?其实还可以有很多的工作可以做。

我:“你都被提问了这么久,你怎么没给人家出个编程题试试呢?”
师弟:“也对哦,我的思想似乎总是转的比较慢。我先去问问,她最近是不是也在鼓捣什么系统。”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/493986.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LDR6020双盲插音频随便插充电听歌随便插

随着智能手机的普及和功能的日益丰富&#xff0c;手机已经成为我们日常生活中不可或缺的一部分。音乐、电影、游戏等娱乐内容更是丰富了手机的使用体验。而在这其中&#xff0c;音频转接器的作用愈发凸显&#xff0c;特别是在边听边充的场景下&#xff0c;一款高效且便捷的手机…

【Docker】03 容器操作

文章目录 一、流转图二、基本操作2.1 查看本地容器进程2.2 启动容器2.2.1 交互式启动容器2.2.2 后台启动容器 2.3 进入容器2.4 停止启动重启容器2.5 退出容器2.6 删除容器2.7 提交容器&#xff08;打包成镜像&#xff09;2.8 拷贝文件2.8.1 拷贝容器内文件到宿主机2.8.2 拷贝宿…

学成在线_课程计划查询_前端页面无法跳转

问题描述 在进行课程计划查询的接口开发时通过了http-client测试但点开课程修改界面后点击保存并进行下一步时无法跳转到修改课程计划查询的页面。 问题原因 课程信息修改的Controller层没有实现 QAQ&#xff08;可能是老师在讲这一块的时候没有提这一点&#xff08;我也记…

C# paddlerocrsharp识别身份证号

https://gitee.com/raoyutian/paddle-ocrsharp 项目搭建 新建控制台项目 安装paddleocrsharp 下载训练好的模型 解压放到对应的文件夹中&#xff0c;都修改为如果较新则复制 编写代码OCRHelper.cs using PaddleOCRSharp;namespace OCRTest02;public class OCRHelper {//…

golang gin单独部署vue3.0前后端分离应用

概述 因为公司最近的项目前端使用vue 3.0&#xff0c;后端api使用golang gin框架。测试通过后&#xff0c;博文记录&#xff0c;用于备忘。 步骤 npm run build&#xff0c;构建出前端项目的dist目录&#xff0c;dist目录的结构具体如下图 将dist目录复制到后端程序同级目录…

Vue-3

自定义指令 全局注册指令 文件路径&#xff1a;src/main.js import Vue from vue import App from ./App.vue Vue.config.productionTip false// 全局注册指令 Vue.directive(myFocus, {// inserted 会在指令所在的元素&#xff0c;被插入到页面中时触发inserted(el) {el.f…

【postgresql】数据表id自增与python sqlachemy结合实例

需求&#xff1a; postgresql实现一个建表语句&#xff0c;表名&#xff1a;student,字段id,name,age&#xff0c; 要求&#xff1a;每次添加一个数据id会自动增加1 在PostgreSQL中&#xff0c;您可以使用SERIAL或BIGSERIAL数据类型来自动生成主键ID。以下是一个创建名为stude…

React PureComponent 和 React.memo()区别

1 注意 ● PureComponent和memo仅作为性能优化的方式存在 ● 不要依赖它来阻止渲染&#xff0c;会产生BUG ● PureComponnet 和memo 都是通过对 props 值的浅比较来决定该组件是否需要更新的。 2 PureComponent 和React.memo() 区别 PureComponent 和React.memo()都是React优化…

MATLAB环境下基于分形理论的图像处理研究

分形理论的提出走出了传统整数维度空间的束缚&#xff0c;对物体的描述更加符合自然事物的复杂性与多样性。传统的维度空间是整数的&#xff0c;人们会将空间认为是三维的&#xff0c;平面认定为是二维的&#xff0c;直线是一维的&#xff0c;点被认为是零维的。而这种维度空间…

“智能语音指令解析“ 基于NLP与语音识别的工单关键信息提取

“智能语音指令解析“ 基于NLP与语音识别的工单关键信息提取 1. 背景介绍1.1 场景痛点1.2 方案选型 2. 准备开发环境3. PaddleSpeech 语音识别快速使用4. PaddleNLP 信息抽取快速使用5. 语音工单信息抽取核心功能实现6. 语音工单信息抽取网页应用6.1 网页前端6.2 网页后端6.3 a…

【软件测试】--功能测试2--常用设计测试用例方法

一、解决穷举场景 重点&#xff1a;使用等价类划分法 1.1 等价类划分法 重点&#xff1a;有效等价和单个无效等价各取1个即可。 步骤&#xff1a;1、明确需求2、确定有效和无效等价3、根据有效和无效造数据编写用例 1.2 案例&#xff08;qq合法验证&#xff09; 需求&#xff…

vulnhub----hackme2-DHCP靶机

文章目录 一&#xff0c;信息收集1.网段探测2.端口扫描3.目录扫描 二&#xff0c;信息分析三&#xff0c;sql注入1.判断SQL注入2.查询显示位3.查询注入点4.查询库5.查询表6.查字段7. 查user表中的值8.登陆superadmin用户 四&#xff0c;漏洞利用文件上传命令执行蚁剑连接 五&am…