思维导图
客户端
#include "head.h"
//用户提示界面
void help_info1()
{printf("\t-----------------------------------------------\n");printf("\t| HENRY 在线辞典 |\n");printf("\t|版本:0.0.1 |\n");printf("\t|作者:Demons457 |\n");printf("\t|功能: |\n");printf("\t| [1] 登录 |\n");printf("\t| [2] 注册 |\n");printf("\t| [3] 退出 |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面 |\n");printf("\t------------------------------------------------\n");return;
}
void help_info2()
{printf("\t-----------------------------------------------\n");printf("\t| 欢迎进入单词查询系统,很高兴为您服务 |\n");printf("\t|版本:0.0.1 |\n");printf("\t|作者:Demons457 |\n");printf("\t|功能: |\n");printf("\t| [1] 查单词 |\n");printf("\t| [2] 查询历史记录 |\n");printf("\t| [3] 退出查询系统 |\n");printf("\t|注意:用户只有登录成功后才能进入查单词界面 |\n");printf("\t------------------------------------------------\n");return;
}//用户输入指令
enum{LOGIN = 1, //登陆REGISTER = 2, //注册QUIT = 3, //退出QUERY = 1, //查询单词HISTORY = 2, //查询历史
};int init_tcp(char *ip,char *port)
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket"); exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind"); exit(EXIT_FAILURE);}return sockfd;
}int do_register(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在注册,请输入用户名和密码\n");head->type = USER_REGISTER;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';//发给服务器端if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据,TCP是可靠的连接,若是数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,注册成功!\n"); return 0;}else{printf("\n很遗憾,这个用户名已经被其它用户注册过了,请重新注册"); return -1;}}
int do_query(int sockfd)
{int n = 0;int fd;int count = 0;char buf[1024] = {0};char buf1[128]={0};char buf2[128]={0};char buf3[]="\n";fd=open("/home/linux/22061/2/client/history.txt",O_RDWR|O_CREAT|O_TRUNC,0666);if(fd<0){perror("Fail to open");return -1;}//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在查询单词\n");head->type = USER_WORD;head->size = sizeof(mhead_t);printf("pelse input word : ");fgets(head->word,sizeof(head->word),stdin);head->word[strlen(head->word) - 1] = '\0';strcpy(buf1,head->word);if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据//未完全接收的话,可以在接收n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}//把服务器返回的信息打印出来if(head->type == USER_SUCCESS){printf(" word:%s\n",head->word); time_t t;time(&t);sprintf(buf2,"\n%s\n",ctime(&t));write(fd,buf1,strlen(buf1));write(fd,buf2,strlen(buf2));write(fd,head->word,strlen(head->word));write(fd,buf3,strlen(buf3));close(fd);return 0;}else{printf("\n很遗憾,没有此单词,请重新输入\n"); return -1;}}
int do_history(int sockfd)
{int fd,n;char buf[1024]={0};fd=open("/home/linux/22061/2/client/history.txt",O_RDONLY);if(fd<0){perror("Fail to open");return -1;}while(1){n=read(fd,buf,sizeof(buf));if(0==n)break;puts(buf);}return 0;
}
int do_task2(int sockfd)
{int cmd;while(1){//提示界面帮助,用户选择help_info2(); printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){//用户查询单词case QUERY:if(do_query(sockfd) < 0)continue;break;//用户登陆case HISTORY:if(do_history(sockfd)<0)continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}return 0;
}int do_login(int sockfd)
{int n = 0;int count = 0;char buf[1024] = {0};//定义发送的协议头mhead_t *head = (mhead_t *)buf;printf("\n您正在登陆,请输入用户名和密码\n");head->type = USER_LOGIN;head->size = sizeof(mhead_t);printf("Input username : ");fgets(head->username,sizeof(head->username),stdin);head->username[strlen(head->username) - 1] = '\0';printf("Input password : ");fgets(head->password,sizeof(head->password),stdin);head->password[strlen(head->password) - 1] = '\0';//发给服务器端if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}bzero(&buf,sizeof(buf));while(1){//接收数据//未完全接收的话n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){perror("Fail to send");exit(EXIT_FAILURE);}//若是数据未发送完成,再次接收的时候可补充count += n;if(count == sizeof(mhead_t))break;}if(head->type == USER_SUCCESS){printf("\n恭喜您,登陆成功!\n"); do_task2(sockfd);return 0;}else{printf("\n很遗憾,您的帐号或密码错误,请重新输入"); return -1;}}
int do_task(int sockfd)
{int cmd;while(1){//提示界面帮助,用户选择help_info1(); printf("\n\n请选择>");scanf("%d",&cmd);//吃掉回车键getchar();switch(cmd){//用户注册case REGISTER:if(do_register(sockfd) < 0)continue;break;//用户登陆case LOGIN:if(do_login(sockfd)<0)continue;break;case QUIT:exit(EXIT_SUCCESS);default:printf("Unknow cmd.\n");continue;}}return 0;
}//由于后面要传递参数
int main(int argc, char *argv[])
{int sockfd; int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 3){fprintf(stderr,"Usage : %s argv[1] argv[2]\n",argv[0]); exit(EXIT_FAILURE);}sockfd = init_tcp(argv[1],argv[2]);do_task(sockfd);return 0;
}
服务器端
#include "head.h"void signal_handler(int signum)
{waitpid(-1,NULL,WNOHANG);return;
}
int init_tcp(char *ip,char *port)
{int sockfd;struct sockaddr_in server_addr;if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0){perror("Fail to socket");exit(EXIT_FAILURE);}bzero(&server_addr,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(port));server_addr.sin_addr.s_addr = inet_addr(ip);if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0){perror("Fail to bind");exit(EXIT_FAILURE);}listen(sockfd,5);printf("listen....\n");return sockfd;
}//数据库中手动创建2个表:user_table,word_table
int main(int argc, char *argv[])
{int pid; sqlite3 *pdb;int listenfd,connect_fd;int addr_len = sizeof(struct sockaddr);struct sockaddr_in peer_addr;if(argc < 4){fprintf(stderr,"Usage : %s ip port system.db.\n",argv[0]);exit(EXIT_FAILURE);}//探测子进程的改变状态,回收僵尸态子进程if(signal(SIGCHLD,signal_handler) == SIG_ERR){perror("Fail to signal");exit(EXIT_FAILURE);}if(sqlite3_open(argv[3],&pdb) != SQLITE_OK){fprintf(stderr,"sqlite3 open %s : %s.\n",argv[3],sqlite3_errmsg(pdb));exit(EXIT_FAILURE);}//初始化tcp连接,得到监听套接字listenfd = init_tcp(argv[1],argv[2]);//提取客户段的链接请求,创建子进程和客户端交互while(1){if((connect_fd = accept(listenfd,(struct sockaddr *)&peer_addr,&addr_len)) < 0){perror("Fail to accept");exit(EXIT_FAILURE);}if((pid = fork()) < 0){perror("Fail to fork");exit(EXIT_FAILURE);}//创建子进程处理客户端的请求if(pid == 0){close(listenfd);do_client(connect_fd,pdb);}close(connect_fd);}exit(EXIT_SUCCESS);
}
#include "head.h" int do_register(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{char *errmsg;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf; sprintf(sql,"select * from user_table where NAME='%s';",_username);if(sqlite3_get_table(pdb,sql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}//没有这样的用户名if(nrow == 0){//录入数据库bzero(sql,sizeof(sql));sprintf(sql,"insert into user_table values('%s','%s');",_username,_password);EXEC_SQL(pdb,sql,errmsg);printf("ok ........\n");head->type = USER_SUCCESS;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//注册失败,用户名存在}else{head->type = USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0) < 0){perror("Fail to send");exit(EXIT_FAILURE);}//表示未知printf("???????\n");}//插入到数据库之后,释放dbresult结果sqlite3_free_table(dbresult);return 0;
}int do_login(int sockfd,sqlite3 *pdb,char *_username,char *_password)
{ char *errmsg;int i,j;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};mhead_t *head = (mhead_t *)buf; char *zsql="select * from user_table";int index=0;//查找数据库中是否有该帐号// sprintf(sql,"select * from user_table where NAME='%s';",_username);if(sqlite3_get_table(pdb,zsql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}//登陆for(i=0;i<=nrow;i++){for(j=0;j<ncolumn;j++){if(strcmp(dbresult[index],_username)==0&&strcmp(dbresult[index+1],_password)==0){printf("登陆成功\n");head->type=USER_SUCCESS;printf("%d\n",head->type);if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}sqlite3_free_table(dbresult);return 0;}}index++;}//帐号密码错误head->type=USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("??????\n");sqlite3_free_table(dbresult);return 0;
}
int do_word(int sockfd,sqlite3 *pdb,char *_word)
{char *errmsg;int i,j;char buf[1024];char **dbresult;int nrow = 0,ncolumn = 0;char sql[1024] = {0};char *zsql="select * from dict_table";int index;mhead_t *head = (mhead_t *)buf; //查找数据库中是否有该单词//sprintf(sql,"select * from dict_table where word='%s';",_word);if(sqlite3_get_table(pdb,zsql,&dbresult,&nrow,&ncolumn,&errmsg) != 0){fprintf(stderr,"sqlite3 get table error : %s.\n",errmsg);exit(EXIT_FAILURE);}for(i=0;i<=nrow;i++){for(j=0;j<ncolumn;j++){if(strcmp(dbresult[index],_word)==0){//查单词printf("ok\n");head->type=USER_SUCCESS;strcpy(head->word,dbresult[index+1]);if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("%d\n",index);sqlite3_free_table(dbresult);return 0;}index++;}}//查找失败,没有该单词head->type=USER_FAILURE;if(send(sockfd,buf,sizeof(mhead_t),0)<0){perror("Fail to send");exit(EXIT_FAILURE);}printf("?????\n");sqlite3_free_table(dbresult);return 0;
}
int do_client(int sockfd,sqlite3 *pdb)
{int n;int count = 0;char buf[1024];mhead_t *head = (mhead_t *)buf; while(1){count = 0;//接收协议头while(1){n = recv(sockfd,buf + count,sizeof(mhead_t) - count,0);if(n <= 0){exit(EXIT_FAILURE);}count += n;printf("count : %d mhead_t : %ld\n",count,sizeof(mhead_t));if(count == sizeof(mhead_t))break;}switch(head->type){case USER_REGISTER:do_register(sockfd,pdb,head->username,head->password); break;case USER_LOGIN:do_login(sockfd,pdb,head->username,head->password);break;case USER_WORD:do_word(sockfd,pdb,head->word);break;defalut:exit(EXIT_SUCCESS);} }return 0;
}