功能:基于网络编程和数据库实现在线词典功能,客户端可以注册,登入,查询历史信息等操作,服务器基于多进程实现多客户端的并发访问,并使用sqlite数据库实现对用户信息的管理。
客户端程序
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #define R 1//register #define L 2//login #define Q 3//query #define H 4//history //定义通信双方信息结构体 typedef struct{ int type; char name[32]; char data[256];//存密码或日期 }MSG; int do_register(int sockfd,MSG * msg) { msg->type = R; printf("plz input ID\n"); scanf("%s",msg->name); getchar(); printf("plz input password\n"); scanf("%s",msg->data); getchar(); if(send(sockfd,msg,sizeof(MSG),0) < 0) { printf("failed to send\n"); return -1; } if(recv(sockfd,msg,sizeof(MSG),0) < 0) { printf("failed to recv\n"); return -1; } //msg->data 接收服务器反馈信息 printf("%s\n",msg->data); return 0; } int do_login(int sockfd,MSG * msg) { msg->type = L; printf("plz input ID\n"); scanf("%s",msg->name); getchar(); printf("plz input password\n"); scanf("%s",msg->data); getchar(); if(send(sockfd,msg,sizeof(MSG),0) < 0) { printf("failed to send\n"); return -1; } if(recv(sockfd,msg,sizeof(MSG),0) < 0) { printf("failed to recv\n"); return -1; } //msg->data 接收服务器反馈信息 if(strncmp(msg->data,"OK",3) == 0) { printf("login successfully\n"); return 1; } else { printf("fail to login\n"); return 0; } } int do_query(int sockfd,MSG * msg) { msg->type = Q; while(1) { printf("input the word(end with #)\n"); scanf("%s",msg->data); getchar(); if(strcmp(msg->data,"#") == 0) { break; } if(send(sockfd,msg,sizeof(MSG),0) < 0) { perror("send"); return -1; } if(recv(sockfd,msg,sizeof(MSG),0) < 0) { perror("recv"); return -1; } printf("the explaination: %s",msg->data); } return 1; } int do_history(int sockfd,MSG * msg) { msg->type = H; send(sockfd,msg,sizeof(MSG),0); while(1) { recv(sockfd,msg,sizeof(MSG),0); if(msg->data[0] == '\0') break; printf("%s",msg->data); } printf("do_history successfully\n"); return 1; } int main(int argc,char * argv[]) { if(argc != 3) { printf("usage: %s serverip port\n",argv[0]); return -1; } int sockfd = -1; if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); return -1; } struct sockaddr_in sin; bzero(&sin,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argv[1]); sin.sin_port = htons(atoi(argv[2])); if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin)) < 0) { perror("connect"); close(sockfd); return -1; } int cmd; MSG msg; _next2: while(1) { printf("*************************\n"); printf("1:register 2:login 3:quit\n"); printf("*************************\n"); printf("plz input a number\n"); scanf("%d",&cmd); switch(cmd) { case 1: do_register(sockfd,&msg); break; case 2: if(do_login(sockfd,&msg) == 1) goto _next; break; case 3: close(sockfd); exit(0); break; default: printf("err number\n"); break; } } _next: while(1) { printf("*******************************\n"); printf("1:query 2:history 3:quit\n"); printf("********************************\n"); printf("plz input a number\n"); scanf("%d",&cmd); switch(cmd) { case 1: do_query(sockfd,&msg); break; case 2: do_history(sockfd,&msg); break; case 3: goto _next2; break; default: printf("err cmd\n"); } } return 0; }
服务器程序
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sqlite3.h> #include <unistd.h> #include <signal.h> #include <time.h> #define PORT 5001 #define database "./mydb.db" #define R 1//register #define L 2//login #define Q 3//query #define H 4//history //定义通信双方信息结构体 typedef struct{ int type; char name[32]; char data[256];//存密码或日期 }MSG; void sig_chld_handler(int sig) { if(sig == SIGCHLD) waitpid(-1,NULL,WNOHANG); } int do_client(int newfd,sqlite3 * db); int do_register(int sockfd,MSG * msg,sqlite3 * db); int do_login(int sockfd,MSG * msg,sqlite3 * db); int do_query(int sockfd,MSG * msg,sqlite3 * db); int do_history(int sockfd,MSG * msg,sqlite3 * db); int get_date(char date[]); int do_search_word(MSG * msg, char * word); int history_callback(void * arg,int f_num,char ** f_value,char ** f_name); int main() { sqlite3 * sql; char * errmsg; if(sqlite3_open(database,&sql) != SQLITE_OK) { printf("%s\n",sqlite3_errmsg(sql)); return -1; } if(sqlite3_exec(sql,"create table user(ID text primary key,password text);",NULL,NULL,&errmsg) != SQLITE_OK) { printf("%s",errmsg); } if(sqlite3_exec(sql,"create table history(ID text,data text, word text);",NULL,NULL,&errmsg) != SQLITE_OK) { printf("%s",errmsg); } int sockfd = -1; if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("socket"); return -1; } int optval = 1; setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)); struct sockaddr_in sin; bzero(&sin,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(PORT); if(bind(sockfd,(const struct sockaddr *)&sin,sizeof(sin)) < 0) { perror("bind"); return -1; } if(listen(sockfd,5) < 0) { perror("listen"); return -1; } // int cmd; // MSG msg; int newfd = -1; socklen_t len = sizeof(sin); while(1) { if((newfd = accept(sockfd,(struct sockaddr *)&sin,&len)) < 0) { perror("accept"); continue; } pid_t pid; if((pid = fork()) < 0) { perror("fork"); continue; } else if(0 == pid) { close(sockfd); do_client(newfd,sql); } else { close(newfd); signal(SIGCHLD,sig_chld_handler); } } } int do_client(int newfd,sqlite3 * db) { MSG msg; int ret; while((ret = recv(newfd,&msg,sizeof(msg),0)) > 0) { switch(msg.type) { case R: do_register(newfd,&msg,db); break; case L: do_login(newfd,&msg,db); break; case Q: do_query(newfd,&msg,db); case H: do_history(newfd,&msg,db); break; default : printf("invalid msg\n"); } } if(ret == 0) printf("client is exited\n"); else perror("recv"); close(newfd); exit(0); return 0; } int do_register(int sockfd,MSG * msg,sqlite3 * db) { char * errmsg; char sql[128] = {0}; sprintf(sql,"insert into user values('%s','%s');",msg->name,msg->data); if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK) { printf("%s",errmsg); strcpy(msg->data,"user already exist"); } else { printf("register successfully\n"); strcpy(msg->data,"OK"); } send(sockfd,msg,sizeof(MSG),0); return 0; } int do_login(int sockfd,MSG * msg,sqlite3 * db) { char * errmsg; char sql[128] = {0}; char ** presults; int nrow; int ncolumn; sprintf(sql,"select * from user where ID = '%s' and password = '%s'",msg->name,msg->data); if(sqlite3_get_table(db,sql,&presults,&nrow,&ncolumn,&errmsg) != SQLITE_OK) { perror("sqlite3_get_table"); return -1; } if(nrow == 1) { printf("login successfully\n"); strcpy(msg->data,"OK"); send(sockfd,msg,sizeof(MSG),0); return 1; } else { printf("faied to login\n"); strcpy(msg->data,"failed to login"); send(sockfd,msg,sizeof(MSG),0); return 0; } } int do_query(int sockfd,MSG * msg,sqlite3 * db) { char word[64]; strcpy(word,msg->data); int found = 1; char date[128]; char sql[128]; char * errmsg; if((found = do_search_word(msg,word)) == 1)//找到后,将单词,查询时间,用户信息存储到数据表history { printf("word %s found\n",word); get_date(date); sprintf(sql,"insert into history values('%s','%s','%s');",msg->name,date,word); if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK) { printf("%s\n",errmsg); } } else { strcpy(msg->data,"NOT FOUND\n"); } send(sockfd,msg,sizeof(MSG),0); return 0; } int get_date(char date[]) { time_t t; time(&t); struct tm * tp; tp = localtime(&t); sprintf(date,"%04d-%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; } int do_search_word(MSG * msg, char * word) { FILE * fp; char temp[512]; int len = strlen(word); char * p = temp + len; int result; if((fp = fopen("./dict.txt","r")) == NULL) { perror("fopen"); return -1; } while(fgets(temp,sizeof(temp),fp) != NULL) { if((result = strncmp(temp,word,len)) == 0 && temp[len] == ' ') { //跳过空格,定位到注释 while(*p == ' ') { p++; } strcpy(msg->data,p); fclose(fp); return 1; } else if(result < 0) continue; else break; } fclose(fp); return 0; } int do_history(int sockfd,MSG * msg,sqlite3 * db) { char sql[128] = {0}; char * errmsg; sprintf(sql,"select * from history where ID = '%s';",msg->name); if(sqlite3_exec(db,sql,history_callback,(void *)&sockfd,&errmsg) != SQLITE_OK) { printf("%s",errmsg); } else printf("query successfully\n"); msg->data[0] = '\0'; send(sockfd,msg,sizeof(MSG),0); return 1; } int history_callback(void * arg,int f_num,char ** f_value,char ** f_name) { int sockfd = *(int *)arg; MSG msg; sprintf(msg.data,"%s , %s",f_value[1],f_value[2]); send(sockfd,&msg,sizeof(msg),0); }