1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > C语言实现词典-TCP通信的方式实现

C语言实现词典-TCP通信的方式实现

时间:2022-06-08 17:42:22

相关推荐

C语言实现词典-TCP通信的方式实现

目录

C语言——在线词典

一、需求分析

二、客户端功能设计

三、设计数据库mydict.db

四、引入词典文件-dict.txt

五、代码实现

1、 客户端:

2、 服务器端:

六、效果展示

C语言——在线词典

功能介绍:基于Linux操作系统、网络编程和数据库实现在线词典,客户端可以进行注册、登录、查询、查看历史记录和退出功能,服务端基于TCP通信,多线程实现并发访问客户端,并利用sqlite3数据库实现对用户信息的管理。

一、需求分析

1.注册:若用户名已经注册过,可重新注册

2.登录:用户名或密码错误需重新登录

3.查询:输入要查的单词,#键结束查询

4.历史:可以查询当前用户历史查找过的单词

5.退出:退出在线词典

二、客户端功能设计

三、设计数据库mydict.db

这里数据库已经设计好了,创建了两个表,一个是user表,用来存放用户名和密码;一个是record表,用来存放查询过的的单词、查询时间和查询用户。

四、引入词典文件-dict.txt

部分词典内容展示,这里截图显示。

五、代码实现

1、 客户端:

//客户端#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <netinet/in.h>#define N 20#define M 200#define R 1 //注册#define L 2 //登录#define Q 3 //查询单词#define H 4 //历史记录#define E 5 //退出typedef struct{int type;//消息类型char name[N];//用户名char text[M];//单词 或 密码}MSG;#define LEN_SMG sizeof(MSG)typedef struct sockaddr SA;//用户注册void do_register(int sockfd,MSG *pbuf){pbuf->type = R;printf("用户名:");scanf("%s",pbuf->name);printf("密码:");scanf("%s",pbuf->text);send(sockfd,pbuf,LEN_SMG,0);recv(sockfd,pbuf,LEN_SMG,0);printf("%s\n",pbuf->text);sleep(1);}//用户登录int do_login(int sockfd,MSG *pbuf){pbuf->type = L;printf("用户名:");scanf("%s",pbuf->name);printf("密码:");scanf("%s",pbuf->text);send(sockfd,pbuf,LEN_SMG,0);//发送给服务器recv(sockfd,pbuf,LEN_SMG,0);//从服务器接收if(pbuf->type == 8){printf("%s\n",pbuf->text);sleep(1);return 1;}else{printf("%s\n",pbuf->text);return 0;}}//查询单词void do_query(int sockfd,MSG *pbuf){pbuf->type = Q;while(1){printf("请输入你要查询的单词(输入#结束):");scanf("%s",pbuf->text);getchar();//客户端输入#返回上一级菜单if(strncmp(pbuf->text,"#",1) == 0)break;//将要查询的单词发送给服务器send(sockfd,pbuf,LEN_SMG,0);//等待接受服务器,传递回来的单词的注释信息recv(sockfd,pbuf,LEN_SMG,0);printf("就是这个意思:%s\n",pbuf->text);}}//查询历史记录int do_history(int sockfd,MSG *pbuf){pbuf->type = H;send(sockfd,pbuf,LEN_SMG,0);//接受服务器,传递回来的历史信息while(1){recv(sockfd,pbuf,LEN_SMG,0);//历史单词全部接受完成if(pbuf->text[0] == '0')break;//输出历史信息printf("%s\n",pbuf->text);}return 0;}//二级菜单void menu_2(int sockfd,MSG *pbuf){while(1){printf("* 欢迎使用电子词典 *\n");printf("****************************************\n");printf("* 1.查询单词 2.查询历史单词 3.退出 *\n");printf("****************************************\n");printf("请选择:");scanf("%d",&pbuf->type);switch(pbuf->type){case 1:do_query(sockfd,pbuf);break;case 2:do_history(sockfd,pbuf);break;case 3:printf(" 即将退出,欢迎再次使用!\n");send(sockfd,pbuf,LEN_SMG,0);sleep(1);close(sockfd);exit(-1);break;default:printf("错误选项!\n");break;}}}//一级菜单void menu_1(int sockfd,MSG *pbuf){int num;//选择功能while(1){printf("* 电子词典项目 *\n");printf("********************************\n");printf("* 1.注册 2.登录 3.退出 *\n");printf("********************************\n");printf("请选择:");scanf("%d",&num);switch(num){case 1:do_register(sockfd,pbuf);break;case 2:while(do_login(sockfd,pbuf) != 1)continue;menu_2(sockfd,pbuf);break;case 3:printf("即将退出,欢迎下次使用!\n");sleep(1);close(sockfd);exit(-1);default:printf("不存在此项操作!\n");break;}}}int main(){int sockfd;//创建套接字sockfd = socket(AF_INET,SOCK_STREAM,0);if(sockfd < 0){printf("fail to socket\n");return -1;}socklen_t len = sizeof(SA);MSG buf;struct sockaddr_in serveraddr;//结构体serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(8888);//端口号serveraddr.sin_addr.s_addr = inet_addr("192.168.2.128");//ip地址//请求服务端建立连接connect(sockfd,(SA *)&serveraddr,len);//与服务器建立连接后,进入菜单界面menu_1(sockfd,&buf);return 0;}

2、 服务器端:

//服务端#include <stdio.h>#include <sqlite3.h>#include <sys/types.h>/* See NOTES */#include <sys/socket.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#include <signal.h>#include <time.h>#include <sys/wait.h>#include <unistd.h>#define PATH_DICT "./dict.txt" //单词表#define PATH_DATA "./mydict.db" //数据库#define N 20#define SIZE 256#define R 1 //注册#define L 2 //登录#define Q 3 //查询单词#define H 4 //历史记录#define E 5 //退出typedef struct{int type;//消息类型char name[N];//用户名char data[SIZE];//单词 或 密码}MSG;#define LEN_SMG sizeof(MSG)typedef struct sockaddr SA;//注册功能 Rvoid do_register(int connfd,MSG *pbuf,sqlite3 *pdb){char *errmsg,**result;//nrow 查找出的总行数 ncolumn 存储列int nrow = 0,ncolumn = 0;char sql[1280];sprintf(sql,"insert into user values('%s','%s');",pbuf->name,pbuf->data);printf("%s\n",sql);if(sqlite3_exec(pdb,sql,NULL,NULL,&errmsg) != SQLITE_OK){printf("%s\n",errmsg);strcpy(pbuf->data,"user name already exist");}else{printf("client register ok!\n");strcpy(pbuf->data,"OK!");}if(send(connfd,pbuf,LEN_SMG,0) < 0){printf("fail to send\n");return;}return;}//登录 Lvoid do_login(int connfd,MSG *pbuf,sqlite3 *pdb){char *errmsg,**result;char sql[1280]={};int nrow = 0,ncloumn = 0;sprintf(sql,"select * from user where name = '%s'and pass = '%s';",pbuf->name,pbuf->data);printf("%s\n",sql);if(sqlite3_get_table(pdb,sql,&result,&nrow,&ncloumn,&errmsg) != SQLITE_OK){printf("%s\n",errmsg);exit(-1);}//查询成功,数据库有此用户if(nrow > 0){sprintf(pbuf->data,"\n %s恭喜您,登录成功\n",pbuf->name);pbuf->type = 8;}//密码或者用户名错误else{sprintf(pbuf->data,"用户名或密码错误,请重新输入!\n");}send(connfd,pbuf,LEN_SMG,0);}int do_searchword(int connfd,MSG *pbuf,char word[]){char line[500];//用来保存读取的单词及解释int ret;char *p;//打开文件,读取文件FILE *fp = fopen(PATH_DICT,"r");if(fp == NULL){printf("fopen fail\n");sprintf(pbuf->data,"抱歉,服务器打开词典失败\n");send(connfd,pbuf,LEN_SMG,0);return -1;}//打印出客户端要查询的单词int len = strlen(word);printf("%s,len = %d\n",word,len);//读文件来查询单词while(fgets(line,500,fp) != NULL){ret = strncmp(line,word,len);if(ret < 0){continue;}if(ret == 0|| line[len] != ' '){//表示找到查询的单词p = line + len;while(*p == ' '){p++;}//找到注释,跳过所有空格strcpy(pbuf->data,p);printf("%s\n",pbuf->data);send(connfd,pbuf,LEN_SMG,0);//拷贝完毕后,关闭文件fclose(fp);return 1;}else{break;}}strcpy(pbuf->data,"抱歉,没有找到该单词!\n");send(connfd,pbuf,LEN_SMG,0);fclose(fp);return 0;}//获取系统时间char get_date(char *date){time_t t;struct tm *tp = NULL;time(&t);//进行时间格式转换tp = localtime(&t);sprintf(date,"%02d-%02d-%02d %02d:%02d:%02d",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);return 0;}//查询单词 Qint do_query(int connfd,MSG *pbuf,sqlite3 *pdb){char word[64];int found = 0;char date[128];//用来保存系统时间char sql[1280];char line[200];//用来保存读取的单词及解释char *errmsg;int ret;//拿出pbuf结构体中要查询的单词strcpy(word,pbuf->data);found = do_searchword(connfd,pbuf,word);//找到单词,此时应该将用户名时间和单词插入到历史记录表中去if(found == 1){//获取系统时间get_date(date);sprintf(sql,"insert into record values('%s','%s','%s');",pbuf->name,date,word);printf("%s\n",sql);if(sqlite3_exec(pdb,sql,NULL,NULL,&errmsg) != SQLITE_OK){printf("%s\n",errmsg);return -1;}}//表示没有找到else{sprintf(pbuf->data,"抱歉,没有找到该单词的意思\n");}//将查询结果发送给客户端send(connfd,pbuf,LEN_SMG,0);return 0;}//回调函数,每找到一条记录就执行一次该函数int history_callback(void *arg,int f_column,char **f_value,char **f_name){//f_column 记录包含的字段个数//f_value 每个记录的值//f_name 每个记录的字段名称int connfd;MSG pbuf;connfd = *(int *)arg;sprintf(pbuf.data,"%s,%s",f_value[1],f_value[2]);send(connfd,&pbuf,sizeof(pbuf),0);return 0;}//历史记录 Hvoid do_history(int connfd,MSG *pbuf,sqlite3 *pdb){char sql[1280];char *errmsg;sprintf(sql,"select * from record where name = '%s'",pbuf->name);//查询数据库if(sqlite3_exec(pdb,sql,history_callback,(void *)&connfd,&errmsg) != SQLITE_OK){printf("%s\n",errmsg);exit(-1);}elseprintf("请求成功\n");//所有的记录查询完毕后,给客户端发送结束信息pbuf->data[0] = '\0';send(connfd,pbuf,LEN_SMG,0);}void handler(int arg){wait(NULL);}//TCP通信int main(){int serverfd,connfd;struct sockaddr_in serveraddr,clientaddr;socklen_t len = sizeof(SA);int cmd;char clean[SIZE]={0};pid_t pid;ssize_t bytes;//打开数据库sqlite3 *pdb;int ret;ret = sqlite3_open(PATH_DATA,&pdb);if(ret != SQLITE_OK){printf("sqlite3 error\n");return -1;}//创建套接字serverfd = socket(AF_INET,SOCK_STREAM,0);if(serverfd < 0){printf("fail to socket\n");}//绑定套接字serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(8888);serveraddr.sin_addr.s_addr = inet_addr("192.168.2.128");if(bind(serverfd,(SA *)&serveraddr,len) < 0){printf("fail to bind\n");}//监听服务端套接字if(listen(serverfd,10) < 0){printf("fail to listen\n");}signal(SIGCHLD,handler);//处理僵尸进程MSG pbuf;while(1){//创建新的套接字connfd = accept(serverfd,(SA *)&clientaddr,&len);if(connfd < 0){printf("accept\n");return -1;}//创建子进程pid = fork();if(pid < 0){printf("fail to fork\n");continue;}else if(pid == 0){//子进程close(serverfd);while(1){bytes = recv(connfd,&pbuf,LEN_SMG,0);if(bytes <= 0)break;switch(pbuf.type){case R:do_register(connfd,&pbuf,pdb);break;case L:do_login(connfd,&pbuf,pdb);break;case Q:do_query(connfd,&pbuf,pdb);break;case H:do_history(connfd,&pbuf,pdb);break;default:break;}}close(connfd);exit(1);}else//父进程退出close(connfd);}return 0;}

六、效果展示

1、登录、注册界面效果:

2、登录时,用户名或密码错误效果:

3、查询单词效果:

4、输入#结束查询,返回上一级菜单:

5、查询历史记录:

6、两个界面退出效果:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。