在线词典--(一、流程分析)

在线词典实现框架

 

 应用综合项目:

1、在线英英词典

2、项目功能描述

3、用户注册和登录验证

4、服务器端将用户信息和历史记录保存在数据库中,客户端输入用户名和密码,服务器端在数据库中查找、匹配,返回结果

5、单次在线翻译

6、根据客户端输入的单次在字典文件中搜索

7、历史记录查询

8、项目分析

 

项目流程框架:

客户端

 

 

服务器端:

实现:

在终端,创建数据库,dic.db

创建记录table

create table user  (name char , passwd  char , date char);

create table record (name char , date char , word char);

在原有基础上增加实现

1、在搭建的框架中实现并发,实现多客户端的注册登录
2、同时支持管理员(用户名:root,密码:1)和普通用户
3、管理员可以查询所有用户的使用记录

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>      
  4 #include <sys/socket.h>
  5 #include <sys/socket.h>
  6 #include <netinet/in.h>
  7 #include <arpa/inet.h>
  8 #include <string.h>
  9 
 10 #define N 32
 11 
 12 #define R 1  //usr--register
 13 #define L 2  //usr--login
 14 #define Q 3  //usr--query
 15 #define H 4  //root--history
 16 #define Y 5  //root--login
 17 #define X 6  //root--user record
 18 
 19 //定义通信双方的MSG信息结构体
 20 typedef struct {
 21     int type;
 22     char name[N];
 23     char data[256];
 24 }MSG;
 25 
 26 int do_regiser(int sockfd, MSG *msg);
 27 int do_login(int sockfd, MSG *msg);
 28 int do_login_root(int sockfd, MSG *msg);
 29 int do_query(int sockfd, MSG *msg);
 30 int do_history(int sockfd, MSG *msg);
 31 int do_user_record(int sockfd, MSG *msg);
 32 
 33 
 34 int main(int argc, const char *argv[])
 35 {
 36     int sockfd;
 37     struct sockaddr_in serveraddr;
 38     int num;
 39     MSG msg;
 40 
 41     if(argc != 3)
 42     {
 43         printf("Usage :%s serverip port.\n", argv[0]);
 44         return -1;
 45     }
 46 
 47     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 48     {
 49         perror("fail to socket!\n");
 50         return -1;
 51     }
 52 
 53     bzero(&serveraddr, sizeof(serveraddr));
 54     serveraddr.sin_family = AF_INET;
 55     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);    //点分形式转为二进制数据
 56     serveraddr.sin_port = htons(atoi(argv[2]));  //先将字符型转为int型数据,再HBD->NBD 
 57 
 58     if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
 59     {
 60         perror("connect error!\n");
 61         return -1;
 62     }
 63 
 64     printf("Client starting...\n");
 65 
 66     while(1)
 67     {
 68         printf("***************************************************\n");
 69         printf("*     1.regiser  2.login  3.root login  4.quit    *\n");
 70         printf("***************************************************\n");
 71         printf("Please choose:");
 72 
 73         scanf("%d",&num);
 74         getchar();  //每次输入完毕会产生垃圾字符,清除
 75 
 76         switch(num)
 77         {
 78             case 1:
 79                 do_regiser(sockfd, &msg);
 80                 break;
 81             case 2:
 82                 if(do_login(sockfd,&msg) == 1)
 83                 {
 84                     goto next; //登录成功,跳到二级菜单
 85                 }
 86                 break;
 87             case 3:
 88                 if(do_login_root(sockfd, &msg) == 1)
 89                 {
 90                     goto next_root;
 91                 }
 92             case 4:
 93                 close(sockfd);
 94                 exit(0);
 95                 break;
 96             default:
 97                 printf("Invalid data cmd.\n");
 98         }
 99     }
100 
101 next:   //二级菜单
102     while(1)
103     {
104         printf("***************************************************\n");
105         printf("*        1.query word     2.quit        \n");
106         printf("***************************************************\n");
107         printf("Please choose:");
108 
109         scanf("%d",&num);
110         getchar();  //每次输入完毕会产生垃圾字符,清除
111 
112         switch(num)
113         {
114             case 1:
115                 do_query(sockfd, &msg);
116                 break;
117             case 2:
118                 close(sockfd);
119                 exit(1);
120                 break;
121             default:
122                 printf("Invalid data cmd.\n");
123         }
124 
125     }
126 
127 
128 next_root:   //管理员二级菜单
129     while(1)
130     {
131         printf("***************************************************\n");
132         printf("*    1.query word   2.history  3.user record  4.quit    *\n");
133         printf("***************************************************\n");
134         printf("Please choose:");
135 
136         scanf("%d",&num);
137         getchar();  //每次输入完毕会产生垃圾字符,清除
138 
139         switch(num)
140         {
141             case 1:
142                 do_query(sockfd, &msg);
143                 break;
144             case 2:
145                 do_history(sockfd, &msg);
146                 break;
147             case 3:
148                 do_user_record(sockfd, &msg);
149                 break;
150             case 4:
151                 close(sockfd);
152                 exit(1);
153                 break;
154             default:
155                 printf("Invalid data cmd.\n");
156         }
157 
158     }
159     return 0;
160 }
161 
162 int do_regiser(int sockfd, MSG *msg)
163 {
164     msg->type = R;
165     printf("Intput name:");
166     scanf("%s",msg->name);
167     getchar();
168 
169     printf("Intput password:");
170     scanf("%s",msg->data);
171 
172     if(send(sockfd, msg, sizeof(MSG), 0) < 0)
173     {
174         printf("fail to send.\n");
175         return -1;
176     }
177 
178     if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
179     {
180         printf("fail to recv.\n");
181         exit(1);
182     }
183     
184     //ok! or usr already exist
185     printf("%s\n",msg->data);
186 
187     return 0;
188 
189 }
190 
191 int do_login(int sockfd, MSG *msg)
192 {
193     msg->type = L;
194 
195     printf("Intput name:");
196     scanf("%s",msg->name);
197     getchar();
198 
199     printf("Intput password:");
200     scanf("%s",msg->data);
201 
202     if(send(sockfd, msg, sizeof(MSG), 0) < 0)
203     {
204         printf("fail to send.\n");
205         exit(1);
206     }
207 
208     if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
209     {
210         printf("fail to recv.\n");
211         return -1;
212     }
213 
214     if(strncmp(msg->data, "ok", 3) == 0)
215     {
216         printf("Login ok!\n");
217         return 1;
218     }
219     else
220     {
221         printf("%s\n",msg->data);
222     }
223 
224 
225     return 0;
226 }
227 
228 
229 int do_login_root(int sockfd, MSG *msg)
230 {
231     msg->type = Y;
232 
233     printf("name: root");
234     sprintf(msg->name,"root");
235     getchar();
236 
237     printf("Intput password:");
238     scanf("%s",msg->data);
239 
240     if(send(sockfd, msg, sizeof(MSG), 0) < 0)
241     {
242         printf("fail to send.\n");
243         exit(1);
244     }
245 
246     if(recv(sockfd, msg, sizeof(MSG), 0) < 0)
247     {
248         printf("fail to recv.\n");
249         return -1;
250     }
251 
252     if(strncmp(msg->data, "ok", 3) == 0)
253     {
254         printf("ROOT Login ok!\n");
255         return 1;
256     }
257     else
258     {
259         printf("%s\n",msg->data);
260     }
261 
262 
263     return 0;
264 }
265 
266 int do_query(int sockfd, MSG *msg)
267 {
268     msg->type = Q;
269     puts("--------------------------\n");
270 
271     while(1)
272     {
273         printf("Intput word:");
274         scanf("%s",msg->data);
275 
276         //客户端输入结束并返回上一层
277         if(strncmp(msg->data,"#",1) == 0) //比较前1个字符,相同返0
278             break;
279     
280         //将要查询的单词发送给服务器
281         if(send(sockfd, msg, sizeof(MSG), 0) < 0)
282         {
283             printf("file to send.\n");
284             return -1;
285         }
286         
287         //等待接收服务器传递回来的注释单词信息
288         if(recv(sockfd, msg, sizeof(MSG),0) < 0)
289         {
290             printf("file to recv.\n");
291             return -1;
292         }
293         printf("%s\n",msg->data);
294     }
295 
296     return 0;
297 }
298 
299 int do_history(int sockfd, MSG *msg)
300 {
301     msg->type = H;
302     
303     printf("Intput the user name:\n");
304     printf("** name * query date * word **\n");
305     scanf("%s",msg->name);
306     send(sockfd, msg, sizeof(MSG), 0);
307 
308     //接收服务器传递回来的历史记录
309     while(1)
310     {
311         recv(sockfd, msg, sizeof(MSG), 0);
312 
313         if(msg->data[0] == '\0')
314             break;
315         
316         //输出历史记录信息
317         printf("%s\n", msg->data);
318     }
319     return 0;
320 }
321 
322 //查询用户的登录与密码记录
323 int do_user_record(int sockfd, MSG *msg)
324 {
325     msg->type = X;
326     printf("Intput the user name:\n");
327     printf("** name * password * register date **\n");
328     scanf("%s",msg->name);
329     send(sockfd, msg, sizeof(MSG), 0);
330 
331     //接收服务器传递回来的历史记录
332     while(1)
333     {
334         recv(sockfd, msg, sizeof(MSG), 0);
335 
336         if(msg->data[0] == '\0')
337             break;
338         
339         //输出历史记录信息
340         printf("%s\n", msg->data);
341     }
342     return 0;
343 
344 }
client_root.c
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/types.h>      
  4 #include <sys/socket.h>
  5 #include <sys/socket.h>
  6 #include <netinet/in.h>
  7 #include <arpa/inet.h>
  8 #include <string.h>
  9 #include <unistd.h>
 10 #include <sqlite3.h>
 11 #include <signal.h>
 12 #include <time.h>
 13 
 14 #define N 32
 15 #define DATABASE "dic.db"
 16 
 17 #define R 1  //usr--register
 18 #define L 2  //usr--login
 19 #define Q 3  //usr--query
 20 #define H 4  //root--history
 21 #define Y 5  //root--login
 22 #define X 6  //root--user record
 23 
 24 //定义通信双方的MSG信息结构体
 25 typedef struct {
 26     int type;
 27     char name[N];
 28     char data[256];
 29 }MSG;
 30 
 31 int do_client(int acceptfd, sqlite3 *db);
 32 void do_regiser(int acceptfd, MSG *msg, sqlite3 *db);
 33 int do_login(int acceptfd, MSG *msg, sqlite3 *db);
 34 int do_login_root(int acceptfd, MSG *msg, sqlite3 *db);
 35 int do_query(int acceptfd, MSG *msg, sqlite3 *db);
 36 int do_history(int acceptfd, MSG *msg, sqlite3 *db);
 37 int history_callback(void *arg, int f_num,char** f_value ,char** f_name);
 38 int do_searchword(int acceptfd,MSG *msg, char word[]);
 39 int get_date(char *date);
 40 int do_user_record(int acceptfd, MSG *msg, sqlite3 *db);
 41 int user_record_callback(void *arg, int f_num,char** f_value ,char** f_name);
 42 
 43 
 44 // ./server 192.168.31.123 5001
 45 int main(int argc, const char *argv[])
 46 {
 47     int sockfd;
 48     int acceptfd;
 49     struct sockaddr_in serveraddr;
 50     int num;
 51     MSG msg; 
 52     sqlite3 *db;
 53     pid_t pid;
 54     char *errmsg;
 55     char sql[128];
 56 
 57     if(argc != 3)
 58     {
 59         printf("Usage :%s server ip port.\n", argv[0]);
 60         return -1;
 61     }
 62 
 63     /*打开数据库 */
 64     if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
 65     {
 66         printf("%s\n", sqlite3_errmsg(db));
 67         return -1;
 68     }
 69     else
 70     {
 71         printf("open DATABASE success.\n");
 72     }
 73     
 74     //在dic,db 里面创建表格用户密码 user 与单词记录表 record      
 75     //创建套接字
 76     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 77     {
 78         perror("fail to socket!\n");
 79         return -1;
 80     }
 81 
 82     bzero(&serveraddr, sizeof(serveraddr));
 83     serveraddr.sin_family = AF_INET;
 84     serveraddr.sin_addr.s_addr = inet_addr(argv[1]);    //点分形式转为二进制数据
 85     serveraddr.sin_port = htons(atoi(argv[2]));  //先将字符型转为int型数据,再HBD->NBD 
 86 
 87     /*地址快速重用 */
 88     int b_reuse = -1;
 89     setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
 90 
 91     /*绑定 */
 92     if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
 93     {
 94         perror("file to bind.\n");
 95         return -1;
 96     }
 97     
 98     /*将套接字设置为监听模式*/
 99     if(listen(sockfd, 5) < 0)
100     {
101         perror("fail to listen.\n");
102         return -1;
103     }
104 
105     //处理僵尸进程
106     signal(SIGCHLD, SIG_IGN);
107     //SIG_IGN,信号处理方式设置为忽略,内核就会将僵尸子进程交给init处理
108 
109     printf("Server starting ... OK!\n");
110 
111     while(1)
112     {
113         if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
114         {
115             perror("fail to accept.\n");
116             return -1;
117         }
118         
119         printf("Connect success!\n");
120 
121         if((pid = fork()) < 0)
122         {
123             perror("fail to fork.");
124             return -1;
125         }
126         else if(pid == 0) //子进程
127         {
128             //处理客户端的具体消息
129             close(sockfd);  //关闭不需要的文件描述符,节省资源
130             do_client(acceptfd, db);
131             return 0;
132         }
133         else  //父进程,用来接收客户端的请求
134         {
135              close(acceptfd);
136         }
137     }
138     close(acceptfd);
139     return 0;
140 }
141 
142 int do_client(int acceptfd, sqlite3 *db)
143 {
144     MSG msg;
145     //客户端关闭也会关闭套接字,进而跳出while循环
146     while(recv(acceptfd, &msg, sizeof(msg), 0) > 0) //接收成功
147     {
148         printf("type:%d\n", msg.type);
149         switch(msg.type)
150         {
151             case R:
152                 do_regiser(acceptfd, &msg, db);
153                 break;
154             case L:
155                 do_login(acceptfd, &msg, db);
156                 break;
157             case Y:
158                 do_login_root(acceptfd, &msg, db);
159                 break;
160             case Q:
161                 do_query(acceptfd, &msg, db);
162                 break;
163             case H:
164                 do_history(acceptfd, &msg, db);
165                 break;
166             case X:
167                 do_user_record(acceptfd, &msg, db);
168             default:
169                 printf("Invalid data msg.\n");
170         }
171     }
172 
173     printf("client exit.\n");
174     close(acceptfd);
175     exit(0);
176 
177     return 0;
178 }
179 
180 void do_regiser(int acceptfd, MSG *msg, sqlite3 *db)
181 {
182     char *errmsg;
183     char sql[128];
184     char date[128];
185     //获取系统时间
186     get_date(date);
187 
188     sprintf(sql,"insert into user values('%s','%s' ,'%s');", msg->name, msg->data, date);
189     printf("%s\n",sql);
190 
191     if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
192     {
193         printf("%s\n",errmsg);
194         strcpy(msg->data, "user name already exit.");
195     }
196     else
197     {
198         printf("client register ok!\n");
199         strcpy(msg->data, "ok"); //将OK拷到data中,发给client
200     }
201     
202     if(send(acceptfd, msg, sizeof(MSG), 0)<0)
203     {
204         perror("fail to send");
205         return;
206     }
207 
208     return;
209 }
210 
211 int do_login(int acceptfd, MSG *msg, sqlite3 *db)
212 {
213     char sql[128];
214     char *errmsg;
215     int nrow;
216     int ncloumn;
217     char **resultp;
218 
219     sprintf(sql,"select * from user where name = '%s' and passwd ='%s';",msg->name, msg->data);
220     printf("%s\n",sql);
221 
222     if(sqlite3_get_table(db, sql,&resultp, &nrow, &ncloumn, &errmsg) != SQLITE_OK)
223     {
224         printf("%s\n", errmsg);
225         return -1;
226     }
227     else
228     {
229         printf("get_table ok!\n");
230     }
231 
232     //查询成功,数据库拥有此用户
233     if(nrow == 1)
234     {
235         strcpy(msg->data, "ok");
236         send(acceptfd, msg, sizeof(MSG),0);
237         return 1;
238     }
239     else  //密码或用户名错误
240     {
241         strcpy(msg->data,"usr/passwd wrong.");
242         send(acceptfd, msg, sizeof(MSG),0);
243     }
244     return 0;
245 }
246 
247 int do_login_root(int acceptfd, MSG *msg, sqlite3 *db)
248 {
249     char sql[128];
250     char *errmsg;
251     int nrow;
252     int ncloumn;
253     char **resultp;
254 
255     sprintf(sql,"select * from user where name = 'root' and passwd = '%s';", msg->data);
256     printf("%s\n",sql);
257 
258     if(sqlite3_get_table(db, sql,&resultp, &nrow, &ncloumn, &errmsg) != SQLITE_OK)
259     {
260         printf("%s\n", errmsg);
261         return -1;
262     }
263     else
264     {
265         printf("get_table ok!\n");
266     }
267 
268     //查询成功,数据库拥有此用户
269     if(nrow == 1)
270     {
271         strcpy(msg->data, "ok");
272         send(acceptfd, msg, sizeof(MSG),0);
273         return 1;
274     }
275     else  //密码或用户名错误
276     {
277         strcpy(msg->data,"passwd wrong.");
278         send(acceptfd, msg, sizeof(MSG),0);
279     }
280 
281     return 0;
282 }
283 
284 int do_query(int acceptfd, MSG *msg, sqlite3 *db)
285 {
286     char word[64];
287     int found = 0;
288     char date[128];
289     char sql[128];
290     char *errmsg;
291 
292     //拿出msg结构体中,要查询的单词
293     strcpy(word, msg->data);
294 
295     found = do_searchword(acceptfd,msg, word);
296 
297     //表找到了单词,此时应将 name/date/word 插入history.text
298     if(found == 1) 
299     {
300         //获取系统时间
301         get_date(date);
302 
303         //添加历史记录
304         sprintf(sql,"insert into record values('%s','%s','%s')", msg->name, date, word);
305     
306 
307         if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
308         {
309             printf("%s\n",errmsg);
310             return -1;
311         }
312         else
313         {
314             printf("Insert record done.\n");
315         }
316     }
317     else //未找到
318     {
319         strcpy(msg->data,"Not found!");    
320     }
321 
322     //将查询的结果,发送给客户端
323     send(acceptfd, msg, sizeof(MSG), 0);
324 
325     return 0;
326 }
327 
328 int do_history(int acceptfd, MSG *msg, sqlite3 *db)
329 {
330     char sql[128];
331     char *errmsg;
332 
333     
334     sprintf(sql, "select * from record where name = '%s';",msg->name);
335 
336     //查询数据库
337     if(sqlite3_exec(db, sql, history_callback, (void *)&acceptfd, &errmsg) != SQLITE_OK)
338     {
339         printf("%s\n",errmsg);
340     }
341     else
342     {
343         printf("Query record done.\n");
344     }
345 
346     //所有记录查询发送完毕,给客户端发送结束信息
347     msg->data[0] = '\0';
348 
349     send(acceptfd, msg, sizeof(MSG),0);
350 
351     return 0;
352 }
353 
354 int history_callback(void *arg, int f_num,char** f_value ,char** f_name)
355 {
356     //record , name , date , word
357     int acceptfd;
358     MSG msg; //声明结构体变量
359     acceptfd = *((int *)arg);
360 
361     sprintf(msg.data,"%s, %s , %s",f_value[0], f_value[1], f_value[2]); //不是msg->data
362 
363     send(acceptfd, &msg, sizeof(MSG), 0);
364 
365     return 0;
366 }
367 
368 int do_searchword(int acceptfd,MSG *msg, char word[])
369 {
370     FILE * fp;
371     int len = 0;
372     char temp[512] = {};
373     int result;
374     char *p;
375     
376     //打开文件,读取文件,进行对比
377     if((fp = fopen("dict.txt", "r")) == NULL)
378     {
379         perror("fail to fopen.\n");
380         strcpy(msg->data,"Failed to open dict.txt");
381         send(acceptfd, msg, sizeof(MSG), 0);
382         return -1;
383     }
384 
385     //打印出,客户端要查询的单词
386     len = strlen(word);
387     printf("%s, len = %d\n", word, len);
388 
389     //读文件,来查询单词
390     while(fgets(temp,512,fp) != NULL)
391     {
392     
393     //    printf("temp:%s\n", temp); //打印从dict.txt获取的字符
394         result = strncmp(temp ,word, len);
395 
396         if(result < 0) //eg:查询Apple,app<apple,appble<pple
397         {
398             continue;
399         }
400         if(result > 0 || ((result == 0) && (temp[len] != ' ')))
401         {
402             break;
403         }
404 
405         //表示找到查询的单词
406         p = temp + len; //指针移动到单词的末尾
407         while(*p == ' ')
408         {
409             p++;
410         }
411 
412         //找到了注释,跳跃过所有的空格
413         strcpy(msg->data, p);
414         printf("found word:%s\n",msg->data);
415 
416         //注释拷贝完毕,关闭文件
417         fclose(fp);
418         
419         return 1;
420     }
421 
422     fclose(fp);
423 
424     return 0;
425 }
426 
427 int get_date(char *date)
428 {
429     time_t t;
430     struct tm *tp;
431 
432     time(&t);
433 
434     //进行时间格式转换
435     tp = localtime(&t);
436 
437     sprintf(date, "%d-%d-%d %d:%d:%d",tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday, 
438             tp->tm_hour, tp->tm_min, tp->tm_sec);
439 
440 
441     return 0;
442 }
443 
444 
445 //查询用户的注册时间与账户及密码
446 int do_user_record(int acceptfd, MSG *msg, sqlite3 *db)
447 {
448     char sql[128];
449     char *errmsg;
450 
451     
452     sprintf(sql, "select * from user where name = '%s';",msg->name);
453 
454     //查询数据库
455     if(sqlite3_exec(db, sql, user_record_callback, (void *)&acceptfd, &errmsg) != SQLITE_OK)
456     {
457         printf("%s\n",errmsg);
458     }
459     else
460     {
461         printf("Query user record done.\n");
462     }
463 
464     //所有记录查询发送完毕,给客户端发送结束信息
465     msg->data[0] = '\0';
466 
467     send(acceptfd, msg, sizeof(MSG),0);
468 
469     return 0;
470 }
471 
472 int user_record_callback(void *arg, int f_num,char** f_value ,char** f_name)
473 {
474     //record , name , passwd , date
475     int acceptfd;
476     MSG msg; //声明结构体变量
477     acceptfd = *((int *)arg);
478 
479     sprintf(msg.data,"%s, %s , %s",f_value[0], f_value[1], f_value[2]); //不是msg->data
480 
481     send(acceptfd, &msg, sizeof(MSG), 0);
482 
483     return 0;
484 }
server_root.c

 

posted @ 2020-01-31 13:07  朱果果  阅读(720)  评论(0编辑  收藏  举报