项目:TCP在线云词典

在这里插入图片描述

一.要求

1.搭建的框架环境中实现并发,实现多个用户同时查询的功能。
2.服务器分别保存每个用户的使用记录,客户端可以查询日志的功能。
3.基本的查询单词的功能。
4.密码验证的功能,实现登录验证账号和密码是否正确。

二.流程和框架

框架
在这里插入图片描述

客户端
![2023-09-03T10:44:22.png][2]

服务器
在这里插入图片描述

三.思路

1.首先你要准备好单词文件,用于英语单词的查询。
dict.txt

2.该项目涉及多并发问题,可以使用多进程,多线程,IO多路复用中的一种,我这里采用IO多路复用的select实现。

3.实现日志功能,需要建立一个数据库,为每一个用户建立一个表,表中存储用户的各种记录。
4.密码验证,同样使用数据库完成,每次登录时,将和数据库中所有的用户信息比较,若账号密码正确,即可登录。

在这里插入图片描述
Linux的IO多路复用是一种高效的IO处理机制,通过允许一个线程同时监控多个文件描述符(包括套接字、管道等)的IO事件,从而避免了传统的多线程或多进程方式中的频繁的上下文切换和资源消耗。在Linux系统中,IO多路复用主要基于以下三种机制:select、poll和epoll。

  1. select:select是最早引入的IO多路复用机制之一。它通过select系统调用来监控多个文件描述符上的IO事件,一旦有IO事件发生,就会通知应用程序进行处理。然而,select的一个缺点是每次调用都需要将所有的文件描述符从应用程序空间复制到内核空间,造成资源浪费。

  2. poll:poll是对select的改进,它也能够监控多个文件描述符上的IO事件,并将有IO事件发生的文件描述符返回给应用程序。与select不同的是,poll使用了链表数据结构来存储文件描述符,减少了在内核空间和应用程序空间之间的数据复制。

  3. epoll:epoll是Linux特有的高性能IO多路复用机制。它通过epoll系统调用来注册、注销和监控文件描述符上的IO事件。epoll采用事件驱动的方式,只会返回有IO事件发生的文件描述符,避免了无效的遍历和资源浪费。此外,epoll还提供了三种工作模式:EPOLL_CTL_ADD(添加文件描述符)、EPOLL_CTL_MOD(修改文件描述符)和EPOLL_CTL_DEL(删除文件描述符),更加灵活和高效。

IO多路复用在网络编程中特别有用,可以用于实现高并发的服务器。通过IO多路复用,可以在单线程或少量线程的情况下同时处理多个连接的IO事件,提高服务器的并发性能和效率。

总结而言,Linux的IO多路复用是一种有效的IO处理机制,通过select、poll和epoll等机制,可以实现高效的监控和处理多个IO事件,提高系统的并发性能和效率。
四.具体实现代码

head.h

#ifndef __HEAD_H__
#define __HEAD_H__
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>/* 消息对应的结构体(同一个协议) */
typedef struct msg_t
{int type;       char name[32];  //用户名char text[256]; //消息正文char password[32]; //密码
} MSG_t;enum type_t
{my__register=1,  //注册login,         //连接  word,          //查询单词history,       //查询日志   quit,      
};
#endif

client.c

#include "head.h"
struct sockaddr_in saddr;
int socked;
MSG_t msg;
//注册帐号函数
void my_register()
{MSG_t msg;msg.type = my__register;printf("%d\n", msg.type);printf("请输入帐号昵称:\n");scanf("%s", msg.name);printf("请输入帐号密码:\n");scanf("%s", msg.password);send(socked, &msg, sizeof(msg), 0);printf("sendis ok\n");int flage = recv(socked, &msg, sizeof(msg), 0);if (flage < 0){perror("recv is err");return;}else{printf("%s\n", msg.text);}
}//连接帐号函数,判断是否连接成功
int my_login()
{msg.type = login;printf("请输入帐号昵称:\n");scanf("%s", msg.name);printf("请输入帐号密码:\n");scanf("%s", msg.password);send(socked, &msg, sizeof(msg), 0);printf("send id ok\n");int flage = recv(socked, &msg, sizeof(msg), 0);if (flage < 0){perror("recv is err");return -1;}else{printf("%s\n",msg.text);if (strncmp(msg.text, "ok", 2) == 0){printf("登录成功\n");return 1;}else{printf("登录失败\n");return 0;}}
}//查询单词函数
void my_query_word()
{msg.type = word;printf("输入quit退出\n");getchar();while (1){msg.type = word;fgets(msg.text, sizeof(msg.text), stdin);if (msg.text[strlen((msg.text)) - 1] == '\n')msg.text[strlen((msg.text)) - 1] = '\0';if (strcmp(msg.text, "quit") == 0)return;printf("要查询的单词:%s\n",msg.text);send(socked, &msg, sizeof(msg), 0);int flage = recv(socked, &msg, sizeof(msg), 0);if (flage < 0){perror("recv is err");return;}else{printf("%s", msg.text);printf("\n");}}
}//查询日志函数
void my_history_record()
{msg.type = history;printf("\n请再次帐号密码:");scanf("%s", msg.password);send(socked, &msg, sizeof(msg), 0);while (1){int flage = recv(socked, &msg, sizeof(msg), 0);if (flage < 0){perror("recv is err");return;}else{if (strcmp(msg.text, "quit") == 0){break;}printf("%s", msg.text);}}printf("************************************\n");
}//查询函数,查询单词或者日志
void my_send()
{int choose;while (1){printf("************************************\n");printf("* 1: query_word 2: history_record 3: quit *\n");printf("************************************\n");printf("请输入你的选择:");scanf("%d", &choose);switch (choose){case 1:my_query_word();break;case 2:my_history_record();break;case 3:return;}}
}int main(int argc, char const *argv[])
{//1.创建套接字,IPv4socked = socket(AF_INET, SOCK_STREAM, 0);if (socked < 0){perror("socket is err\n");return -1;}//2.connect服务器saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[2]));saddr.sin_addr.s_addr = inet_addr(argv[1]);if ((connect(socked, (struct sockaddr *)&saddr, sizeof(saddr))) < 0){perror("connect is err");return -1;}//3.选择注册,登录,退出int choose;while (1){printf("************************************\n");printf("* 1: register 2: login 3: quit *\n");printf("************************************\n");printf("请输入你的选择:");scanf("%d", &choose);switch (choose){case 1:my_register();break;case 2:if (my_login())my_send();break;case 3:close(socked);exit(0);}}close(socked);return 0;
}

server.c

#include "head.h"
#include <sqlite3.h>
#include <sys/select.h>
#include <time.h>
int sockfp, acceptfp, flage, sockfd, flages;
MSG_t msg, msg1;
sqlite3 *db = NULL;//读日志函数,发送给客户端
void my_history()
{char **result;int hang, lie;char *errmasg;char buf[1024];sprintf(buf, "select * from %s_%s;", msg.name, msg.password);sqlite3_get_table(db, buf, &result, &hang, &lie, &errmasg);printf("开始发送日志\n");for (int i = 0; i <= hang; i++){for (int j = 0; j < lie; j++){sprintf(msg.text, "%s\t", result[i * lie + j]);send(sockfd, &msg, sizeof(msg), 0);}strcpy(msg.text, "\n");send(sockfd, &msg, sizeof(msg), 0);}strcpy(msg.text, "quit");send(sockfd, &msg, sizeof(msg), 0);
}//写日志
void write_history()
{time_t current_time;struct tm *local_time;char time_string[100];char perate[100];char buf[1024];char *errmsg;// 获取当前时间戳current_time = time(NULL);// 将时间戳转换为本地时间local_time = localtime(&current_time);// 格式化本地时间字符串strftime(time_string, sizeof(time_string), "%Y-%m-%d %H:%M:%S", local_time);switch (msg1.type){case my__register:strcpy(perate, "register");break;case login:strcpy(perate, "login");break;case word:strcpy(perate, "word");break;default:strcpy(perate, "quit");break;}sprintf(buf, "insert into %s_%s values(\"%s\",\"%s\");", msg1.name, msg1.password, time_string, perate);if ((sqlite3_exec(db, buf, NULL, NULL, &errmsg)) != SQLITE_OK){fprintf(stderr, "sqlite3_exec is err %s", errmsg);return;}
}int callback(void *data, int argc, char **argv, char **azColName)
{printf("调用callback函数\n");printf("%d\n", argc);char *knownTableName = (char *)data;for (int i = 0; i < argc; i++){printf("%s\n", argv[i]);if (strcmp(argv[i], knownTableName) == 0){strcpy(msg.text, "ok");send(sockfd, &msg, sizeof(msg), 0);printf("send is ok ok\n");printf("%s已登录成功\n", argv[i]);flages = 1;return 0;}}// strcpy(msg.text, "no");// send(sockfd, &msg, sizeof(msg), 0);// printf("send is ok\n");return 0;
}//注册函数
void my_register()
{char buf[512];char *errmsg;sprintf(buf, "create table %s_%s(time char,perate char);", msg.name, msg.password);printf("%s\n", buf);if ((sqlite3_exec(db, buf, NULL, NULL, &errmsg)) != SQLITE_OK){fprintf(stderr, "sqlite3_exec is err %s", errmsg);strcpy(msg.text, "注册失败\n");send(sockfd, &msg, sizeof(msg), 0);return;}elsestrcpy(msg.text, "注册成功\n");send(sockfd, &msg, sizeof(msg), 0);printf("send is ok\n");
}//连接函数只有昵称和密码都匹配才能连接
void my_login()
{printf("调用连接函数\n");char buf[512];char *errmsg;char knownTableName[512];int rc;sprintf(knownTableName, "%s_%s", msg.name, msg.password);strcpy(buf, "SELECT name FROM sqlite_master WHERE type='table';");printf("%s\n", buf);rc = sqlite3_exec(db, buf, callback, knownTableName, &errmsg);if (rc != SQLITE_OK){fprintf(stderr, "SQL error: %s\n", errmsg);}if (!flages){strcpy(msg.text, "no");send(sockfd, &msg, sizeof(msg), 0);}//sleep(1);
}//查询单词函数
void my_word()
{char buf[2048] = {0};int len = strlen(msg.text), flage = 0;FILE *fp = fopen("dict.txt", "r");if (fp == NULL){perror("fopen is err");strcpy(msg.text, "fopen is err");send(sockfd, &msg, sizeof(msg), 0);return;}while (fgets(buf, sizeof(buf), fp)){if ((strncmp(msg.text, buf, len)) == 0){flage = 1;break;}}int i;printf("len=%d\n", len);for (i = len; i < 2048; ++i){if (buf[i] != ' ')break;}//printf("%s\n",buf);printf("%s\n", msg.text);if (flage){strcpy(msg.text, buf + i);}else{strcpy(msg.text, "没有这个单词");}send(sockfd, &msg, sizeof(msg), 0);
}int main(int argc, char const *argv[])
{//1.创建或打开数据库if ((sqlite3_open("./dict.db", &db)) < 0){fprintf(stderr, "sqlite3_open id err %s\n", sqlite3_errmsg(db));return -1;}//2.创建socket套接字sockfp = socket(AF_INET, SOCK_STREAM, 0);if (sockfp < 0){perror("socket is err");return -1;}//3.绑定服务器ip和端口号struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(struct sockaddr_in);if (bind(sockfp, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind is err");return -1;}//4.listen监听if (listen(sockfp, 90)){perror("liste err");return -1;}//4. select多路复用//4.1 创建表fd_set readfds, tempfds;//4.2 清空表FD_ZERO(&readfds);FD_ZERO(&tempfds);//4.3 将关心的文件描述符添加表FD_SET(0, &readfds);FD_SET(sockfp, &readfds);int maxfd = sockfp;while (1){tempfds = readfds;//4.4 select检测   阻塞select(maxfd + 1, &tempfds, NULL, NULL, NULL);//4.5 进行相应的逻辑处理//sockfp,监听套接字响应证明,有客户端要链接if (FD_ISSET(sockfp, &tempfds)){acceptfp = accept(sockfp, (struct sockaddr *)&caddr, &len);if (acceptfp < 0){perror("acceptfp");exit(0);}printf("连接到%d端口号\n", acceptfp);printf("port:%d   ip:  %s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));FD_SET(acceptfp, &readfds);if (acceptfp > maxfd)maxfd = acceptfp;}//检测客户端,检查是哪一个客户端发送的消息for (int i = 5; i <= maxfd; ++i){if (FD_ISSET(i, &tempfds)){sockfd = i;printf("端口号%d相应\n", i);flage = i;int recvbyte = recv(i, &msg, sizeof(msg), 0);if (recvbyte < 0){perror("recv err");return -1;}else if (recvbyte == 0){msg.type = quit;write_history();close(i);FD_CLR(i, &readfds);if (i == maxfd)--maxfd;}else{printf("recvbyte is ok\n");msg1 = msg;printf("******************\n");switch (msg.type){case my__register:my_register();write_history();break;case login:my_login();write_history();break;case word:my_word();write_history();break;case history:my_history();write_history();break;}}}}}return 0;
}

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

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

相关文章

【Python+selenium】生成测试报告

批量执行完用例后&#xff0c;生成的测试报告是文本形式的&#xff0c;不够直观&#xff0c;为了更好的展示测试报告&#xff0c;最好是生成HTML格式的。 unittest里面是不能生成html格式报告的&#xff0c;需要导入一个第三方的模块&#xff1a;HTMLTestRunner 一、导入HTMLT…

蓝牙技术|多快好省的苹果Find My查找定位方案商:北京自在科技

在电子市场里&#xff0c;各种蓝牙定位器品牌争奇斗艳&#xff0c;例如国外的Tile Mate 和 Slim&#xff0c;三星的 Galaxy SmartTag 和 Galaxy SmartTag&#xff0c;Chipolo 的ONE Spot&#xff0c;还有苹果的 AirTag 等等。而国内也有着不少优秀的品牌&#xff0c;如Nutale的…

多输入多输出 | MATLAB实现CNN-LSTM-Attention卷积神经网络-长短期记忆网络结合SE注意力机制的多输入多输出预测

多输入多输出 | MATLAB实现CNN-LSTM-Attention卷积神经网络-长短期记忆网络结合SE注意力机制的多输入多输出预测 目录 多输入多输出 | MATLAB实现CNN-LSTM-Attention卷积神经网络-长短期记忆网络结合SE注意力机制的多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预…

python抠图(去水印)开源库lama-cleaner入门应用实践

1. 关于 Lama Cleaner Lama Cleaner 是由 SOTA AI 模型提供支持的免费开源图像修复工具。可以从图片中移除任何不需要的物体、缺陷和人&#xff0c;或者擦除并替换&#xff08;powered by stable diffusion&#xff09;图片上的任何东西。 特征&#xff1a; 完全免费开源&am…

YOLO物体检测-系列教程2:YOLOV2整体解读

&#x1f388;&#x1f388;&#x1f388;YOLO 系列教程 总目录 YOLOV1整体解读 YOLOV2整体解读 YOLOV2提出论文&#xff1a;YOLO9000: Better, Faster, Stronger 1、YOLOV1 优点&#xff1a;快速&#xff0c;简单&#xff01;问题1&#xff1a;每个Cell只预测一个类别&…

ros----发布者和订阅者模型

话题模型&#xff1a; 如何自定义话题消息 1.定义msg文件 2.在package.xml中添加功能包依赖 <build_depend>message_generation</build_depend> <exec_depend>message_runtime</exec_depend>3.在CMakeList.txt文件中添加编译选项 4.编译生成语言的相…

医院安全不良事件报告系统源码 PHP+ vue2+element+ laravel8+ mysql5.7+ vscode开发

不良事件上报系统通过 “事前的人员知识培训管理和制度落地促进”、“事中的事件上报和跟进处理”、 以及 “事后的原因分析和工作持续优化”&#xff0c;结合预存上百套已正在使用的模板&#xff0c;帮助医院从对护理事件、药品事件、医疗器械事件、医院感染事件、输血事件、意…

JWT安全及案例实战

文章目录 JWT 安全1. Cookie2. Session3. Token4. JWT4.1 JWT概述4.1.1 JWT头4.1.2 有效载荷4.1.3 签名哈希4.1.4 通信流程 4.2 JWT 漏洞描述4.3 JWT 漏洞原理4.4 JWT 安全防御 5. WebGoat 靶场实验5.1 第四关5.2 第五关5.3 第七关 越权与逻辑漏洞 Web漏洞点只有一个入口&#…

12306 抢票小助手: 完整易用的抢票解决方案 | 开源日报 0917

testerSunshine/12306 Stars: 31.4k License: MIT 12306 购票小助手是一个使用 Python 编写的项目&#xff0c;主要功能包括自动打码、自动登录、准点预售和捡漏、智能候补以及邮件通知等。该项目具有以下核心优势&#xff1a; 支持多个版本的 Python提供验证码本地识别功能可…

企业架构LNMP学习笔记46

PHP测试连接代码&#xff1a; php代码测试使用memcached&#xff1a; 示例代码&#xff1a; <?php //实例化类 $mem new memcached(); //调用连接memcached方法 注意连接地址和端口号 $mem->addServer(192.168.17.114,11211); //存数据 var_dump($mem->set(name,l…

AUTOSAR通信篇 - CAN网络通信(五:ComM)

文章目录 模块交互EcuM交互BswM交互NvM交互CanSM交互NM交互 ComM功能Paritial Network Cluster 管理Partial Network Cluster 管理功能ComM PNC状态机在主状态COMM_PNC_NO_COMMUNICATION中PNC的行为PNC网关相关的要求 从断电进入PNC主状态COMM_PNC_NO_COMMUNICATION时在主状态C…

深入了解MySQL中的JSON_ARRAYAGG和JSON_OBJECT函数

在MySQL数据库中&#xff0c;JSON格式的数据处理已经变得越来越常见。JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式&#xff0c;它可以用来存储和表示结构化的数据。MySQL提供了一些功能强大的JSON函数&#xff0c;其中两个关键的函数是…

SpringBoot实战(二十四)集成 LoadBalancer

目录 一、简介1.定义2.取代 Ribbon3.主要特点与功能4.LoadBalancer 和 OpenFeign 的关系 二、使用场景一&#xff1a;Eureka LoadBalancer服务A&#xff1a;loadbalancer-consumer 消费者1.Maven依赖2.application.yml配置3.RestTemplateConfig.java4.DemoController.java 服务…

笔记01:第一行Python

NameError 名字不含特殊符号&#xff08;只能是英文、数字、下划线、中文等&#xff09;名字区分大小写名字先定义后使用 SyntaxError 不符合Python语法书写规范除了语法成分中的保留拼写错误输出中文符号if、for、def等语句末尾忘记冒号 IdentationError 缩进错误&#x…

C# Onnx Yolov8 Detect 物体检测

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System…

开源即时通讯(IM)项目OpenIM源码部署流程

由于OpenIM依赖的组件较多&#xff0c;开发者需求不一&#xff0c;导致OpenIM部署一直被人诟病&#xff0c;经过几次迭代优化&#xff0c;包括依赖的组件compose的一键部署&#xff0c;环境变量设置一次&#xff0c;全局生效&#xff0c;以及脚本重构&#xff0c;目前OpenIM部署…

2023CSP游寄

初赛 DAY -2 才刚考开学测就来初赛。 复赛之后就是月测&#xff0c;这就是初三吗。 初中最后一次 CSP&#xff0c;如果 S 没一等就得摆烂了。希望别因为各种原因爆炸。 中午下午借着刷初赛题的名义摆烂&#xff0c;半道题都没写。 CSP2023RP 初赛 DAY -1 看我发现了什么。…

SpringBoot 集成 SpringSecurity 从入门到深入理解

完整的目录 介绍 SpringSecurity简述 SpringSecuritySpringSecurity 的主要功能说明 项目源码入门案例项目工程路径第一步&#xff1a;加载依赖第二步&#xff1a;创建核心的配置类第三步&#xff1a;增加controller第三步&#xff1a;启动程序小结界面跳转说明密码生成说明 重…

使用Python来写模拟Xshell实现远程命令执行与交互

一、模块 这里使用的是 paramiko带三方库 pip install paramiko二、效果图 三、代码实现&#xff08;这里的IP&#xff0c;用户名&#xff0c;密码修改为自己对应服务器的&#xff09; import paramiko import timeclass Linux(object):# 参数初始化def __init__(self, ip, us…

python 使用requests爬取百度图片并显示

爬取百度图片并显示 引言一、图片显示二、代码详解2.1 得到网页内容2.2 提取图片url2.3 图片显示 三、完整代码 引言 爬虫&#xff08;Spider&#xff09;&#xff0c;又称网络爬虫&#xff08;Web Crawler&#xff09;&#xff0c;是一种自动化程序&#xff0c;可以自动地浏览…