功能:基于网络编程和数据库实现在线词典功能,客户端可以注册,登入,查询历史信息等操作,服务器基于多进程实现多客户端的并发访问,并使用sqlite数据库实现对用户信息的管理。
客户端程序
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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);
}