深圳英文网站推广,建设网站 关于竣工结算的期限,商城网站建设资讯,网站导航是做链接赚钱么一.要求 1.搭建的框架环境中实现并发#xff0c;实现多个用户同时查询的功能。 2.服务器分别保存每个用户的使用记录#xff0c;客户端可以查询日志的功能。 3.基本的查询单词的功能。 4.密码验证的功能#xff0c;实现登录验证账号和密码是否正确。 二.流程和框架
框架
…
一.要求 1.搭建的框架环境中实现并发实现多个用户同时查询的功能。 2.服务器分别保存每个用户的使用记录客户端可以查询日志的功能。 3.基本的查询单词的功能。 4.密码验证的功能实现登录验证账号和密码是否正确。 二.流程和框架
框架
客户端
服务器
三.思路 1.首先你要准备好单词文件用于英语单词的查询。 dict.txt 2.该项目涉及多并发问题可以使用多进程多线程IO多路复用中的一种我这里采用IO多路复用的select实现。 3.实现日志功能需要建立一个数据库为每一个用户建立一个表表中存储用户的各种记录。 4.密码验证同样使用数据库完成每次登录时将和数据库中所有的用户信息比较若账号密码正确即可登录。 Linux的IO多路复用是一种高效的IO处理机制通过允许一个线程同时监控多个文件描述符包括套接字、管道等的IO事件从而避免了传统的多线程或多进程方式中的频繁的上下文切换和资源消耗。在Linux系统中IO多路复用主要基于以下三种机制select、poll和epoll。 selectselect是最早引入的IO多路复用机制之一。它通过select系统调用来监控多个文件描述符上的IO事件一旦有IO事件发生就会通知应用程序进行处理。然而select的一个缺点是每次调用都需要将所有的文件描述符从应用程序空间复制到内核空间造成资源浪费。 pollpoll是对select的改进它也能够监控多个文件描述符上的IO事件并将有IO事件发生的文件描述符返回给应用程序。与select不同的是poll使用了链表数据结构来存储文件描述符减少了在内核空间和应用程序空间之间的数据复制。 epollepoll是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__register1, //注册login, //连接 word, //查询单词history, //查询日志 quit,
};
#endifclient.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 typetable;);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;
}