项目介绍
该项目为HQ嵌入式Linux应用项目,主要运用知识:Sqlite3 数据库基本操作,TCP/IP多并发编程,文件IO, 。
程序流程:
项目代码
client端
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
#define R 1 //register
#define L 2 //log_in
#define Q 3 //query
#define H 4 //history
typedef struct{
int type;
char name[N];
char data[256]; //save password of word
}MSG;
void do_register(int *socketfd, MSG * msg);
int do_login(int *socketfd, MSG * pmsg);
void do_query(int *socketfd, MSG * pmsg);
void do_history();
/* ./server IP地址 端口号 */
int main(int argc, char* argv[])
{
if(argc != 3)
{
printf("please input the ip_addr and port \n");
return 0;
}
int socketfd;
struct sockaddr_in myaddr;
int cmd;
MSG msg;
bzero(&msg, sizeof(msg));
if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket fail");
exit(-1);
}
printf("%s \n%s\n", argv[1], argv[2]);
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = AF_INET;
inet_pton(AF_INET,argv[1],(void *)&myaddr.sin_addr.s_addr);
myaddr.sin_port = htons(atoi(argv[2]));
if((connect(socketfd,(struct sockaddr *)&myaddr,sizeof(myaddr))) < 0)
{
perror("connect fail");
exit(-1);
}
while(1)
{
printf("**********************************\n");
printf("* 1: register 2: login 3: quit *\n");
printf("**********************************\n");
printf("Your cmd: ");
scanf("%d",&cmd);
getchar(); //delete '\n'
switch(cmd)
{
case 1:
do_register(&socketfd, &msg);
break;
case 2:
if(do_login(&socketfd, &msg) == 1)
if(cmd == 2)
{
goto next; //进入二级菜单
}
break;
case 3:
close(socketfd);
exit(0);
break;
default:
printf("invalid input !\n");
break;
}
}
next:
while(1)
{
printf("***********************************************\n");
printf("* 1: query_word 2: history_record 3: quit *\n");
printf("***********************************************\n");
printf("Your cmd: ");
scanf("%d",&cmd);
getchar();
switch (cmd)
{
case 1:
do_query(&socketfd, &msg);
break;
case 2:
do_history(&socketfd, &msg);
break;
case 3:
close(socketfd);
exit(0);
break;
default:
printf("invalid input! \n");
break;
}
}
return 0;
}
void do_register(int *socketfd, MSG * pmsg)
{
int len_msg = sizeof(*pmsg);
pmsg->type = R;
printf("username: ");
scanf("%s", pmsg->name);
getchar();
printf("password: ");
scanf("%s",pmsg->data);
send(*socketfd, pmsg, len_msg, 0);
// printf("username %s\n",pmsg->name);
// printf("password %s\n", pmsg->data);
recv(*socketfd, pmsg, len_msg, 0);
printf("%s\n",pmsg->data);
}
int do_login(int *socketfd, MSG * pmsg)
{
int len_msg = sizeof(*pmsg);
bzero(pmsg,len_msg);
pmsg->type = L;
printf("username: ");
scanf("%s",pmsg->name);
getchar();
printf("password: ");
system("stty -echo"); //隐藏输入
scanf("%s",pmsg->data);
system("stty echo"); //隐藏输入
getchar();
//printf("%s\n%s\n",pmsg->name,pmsg->data);
if((send(*socketfd, pmsg, len_msg, 0)) < 0)
{
perror("send fail");
exit(-1);
}
if(recv(*socketfd,pmsg,len_msg,0) < 0)
{
perror("recv fail");
exit(-1);
}
if(!strncmp(pmsg->data,"OK", strlen("OK")))
{
printf("Login success!\n");
return 1;
}
else
{
printf("Password or username error \n");
return 0;
}
}
void do_query(int *socketfd, MSG * pmsg)
{
char word[64]= {0};
int len_msg = sizeof(*pmsg);
//bzero(pmsg,sizeof(*pmsg));
pmsg->type = Q;
while(1)
{
printf("Enter a word you want to search for('#' to end): ");
scanf("%s", pmsg->data);
getchar();
strcpy(word,pmsg->data);
if(!strncmp(pmsg->data,"#",2))
{
printf("quert end! \n");
break;
}
if(send(*socketfd, pmsg, len_msg, 0) < 0)
{
perror("send fail");
exit(-1);
}
if(recv(*socketfd,pmsg,len_msg,0) < 0)
{
perror("recv fail");
exit(-1);
}
/*结果输出需要美化*/
printf("\n");
printf("%s\n ",word);
printf("%10s \n",pmsg->data);
}
}
void do_history(int *socketfd, MSG * pmsg)
{
int len_msg = sizeof(*pmsg);
pmsg->type = H;
memset(pmsg->data, 0 ,sizeof(pmsg->data));
if(send(*socketfd, pmsg, len_msg, 0) < 0)
{
perror("send fail");
exit(-1);
}
while (1)
{
if(recv(*socketfd,pmsg,len_msg,0) < 0)
{
perror("recv fail");
exit(-1);
}
//printf("msg.data : %s\nmsg.name: %s",pmsg->data, pmsg->name);
if(!strncmp(pmsg->data,"query_over",10))
{
printf("query histoy over! \n");
break;
}
printf("%s \n",pmsg->data);
}
}
server端
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "sqlite3.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#define N 64
#define R 1 //register
#define L 2 //log_in
#define Q 3 //query
#define H 4 //history
#define Netprot 端口号
#define Netip "IP地址"
#define BACKLOG 5
typedef struct{
int type;
char name[N];
char data[256]; //save password of word
}MSG;
void do_register(int* recvfd,sqlite3 * db, MSG * pmsg);
void do_login(int* recvfd, sqlite3 * db, MSG * pmsg);
void do_query(int* recvfd, sqlite3 * db, MSG * pmsg);
void do_history();
void cil_data_handle(int signum);
int main(int argc, char* argv[])
{
/*
signal 回收僵尸进程
*/
signal(SIGCHLD, cil_data_handle);
int socketfd;
sqlite3 * mysql;
struct sockaddr_in server_addr;
if((socketfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket fail");
exit(-1);
}
if(sqlite3_open("info.db", &mysql) != SQLITE_OK)
{
printf("sqlite3 open fail %s \n",sqlite3_errmsg(mysql));
exit(-1);
}
/* 快速复用 设置*/
int b_reuse = 1;
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(Netip);
server_addr.sin_port = htons(Netprot);
if(bind(socketfd,(struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
perror("bind fail");
exit(-1);
}
if(listen(socketfd,BACKLOG) < 0)
{
perror("listen fail");
exit(-1);
}
int recvfd;
pid_t pid;
MSG msg;
while(1)
{
/*
可创建struct sockaddr 变量保存连接客户端的ip信息
*/
if((recvfd = accept(socketfd,NULL,NULL)) < 0 )
{
perror("accept fail");
exit(-1);
}
pid = fork();
if(pid < 0)
{
perror("fork fail");
exit(-1);
}
else if(pid == 0) //child process
{
printf("new client connet\n");
close(socketfd);
while(recv(recvfd, &msg, sizeof(msg), 0))
{
//printf("type = %d\n", msg.type);
switch(msg.type)
{
case R:
do_register(&recvfd ,mysql, &msg);
break;
case L:
do_login(&recvfd ,mysql, &msg);
break;
case Q:
do_query(&recvfd ,mysql, &msg);
break;
case H:
do_history(&recvfd ,mysql, &msg);
break;
}
}
printf("client exit \n");
close(recvfd);
return 0;
}
else //father process
{
close(recvfd);
}
}
return 0;
}
void do_register(int* recvfd, sqlite3 * db, MSG * pmsg)
{
MSG msg = *pmsg;
int len_msg = sizeof(msg);
//printf("do_register :server\n");
//printf("recv username : %s \n",pmsg->name);
//printf("recv password %s \n", pmsg->data);
char sql[400] = {0};
char *errmsg;
sprintf(sql,"insert into user values('%s', '%s');",pmsg->name, pmsg->data);
if((sqlite3_exec(db,sql,NULL,NULL,&errmsg)) != SQLITE_OK)
{
printf("sqlite3 fail: %s \n",errmsg);
strcpy(pmsg->data,"user is already");
}
else
{
strcpy(pmsg->data,"regiseter success!");
}
if(send(*recvfd, pmsg, len_msg, 0) < 0)
{
perror("send fail");
exit(-1);
}
}
void do_login(int* recvfd, sqlite3 * db, MSG * pmsg)
{
printf("do_login :server\n");
// printf("recv username : %s \n",pmsg->name);
// printf("recv password : %s \n", pmsg->data);
int len_msg = sizeof(*pmsg);
char sql[400]={0};
char ** result;
int row;
int cloumn;
char * errmsg;
sprintf(sql,"select * from user where username='%s' and password='%s';",pmsg->name,pmsg->data);
if((sqlite3_get_table(db, sql, &result, &row, &cloumn, &errmsg)) != SQLITE_OK)
{
printf("get_table fail %s \n",errmsg);
exit(-1);
}
if(row == 1)
{
//用户名和密码正确
strncpy(pmsg->data, "OK",3); //千万不能使用sizeof("OK")会出现stack smashing detected
if(send(*recvfd,pmsg,len_msg,0) < 0 )
{
perror("Lsend fail");
exit(-1);
}
sqlite3_free_table(result);
}
else
{
//用户名和密码有误
strncpy(pmsg->data,"ERR",len_msg);
if(send(*recvfd,pmsg,len_msg,0) < 0)
{
perror("Lsend fail");
exit(-1);
}
sqlite3_free_table(result);
}
}
int do_searchword(MSG * pmsg)
{
printf("searchword begin!\n");
//pmsg->data 要查询内容
FILE *fp;
int ret;
char temp[512] = {0};
char word[64] = {0};
strcpy(word,pmsg->data);
//printf("word = %s", word);
char * p;
int len = strlen(word);
if((fp = fopen("dict.txt","r")) == NULL)
{
perror("fopne fail");
exit(-1);
}
/* 按行搜索 */
while(fgets(temp,sizeof(temp)-1,fp) != NULL)
{
printf("find process %s \n",temp);
ret = strncmp(pmsg->data,temp, len);
//printf("ret = %d \n", ret);
if(ret > 0)
{
//没有找到
printf("continue \n");
continue;
}
if(ret == 0 && temp[len] == ' ')
{
//找到了
printf("find the word %s \n",pmsg->data);
break;
}
else //ret < 0
{
printf("There is no such word \n");
return -1;
}
}
p = temp + len; //定义文件指针,用于提取单词后的解释
while(*p == ' ') //abandonment n. abandoning 将指针移动到解释字符串的头部
{
p++;
}
strcpy(pmsg->data, p);
//printf("the word means: %s \n",pmsg->data);
fclose(fp);
return 1;
}
void do_query(int* recvfd, sqlite3 * db, MSG * pmsg)
{
printf("do_query :server\n");
int find;
int len_msg = sizeof(*pmsg);
char *word = pmsg->data;
char *name = pmsg->name;
MSG query_msg;
query_msg = *pmsg;
//recv(*recvfd, pmsg, len_msg, 0);
find = do_searchword(&query_msg);
pmsg = &query_msg;
if(find < 0)
{
strcpy(pmsg->data, "Word not found! ");
}
send(*recvfd,pmsg,len_msg,0);
//获取当前系统时间
time_t systime;
struct tm * rectime;
char time_string[40]={0};
char sql[256] = {0};
char *errmsg;
time(&systime);
rectime = localtime(&systime);
/*printf("%d-%d-%d %d:%d \n",
rectime->tm_year+1900, rectime->tm_mon+1, rectime->tm_mday, rectime->tm_hour, rectime->tm_min);
*/
strftime(time_string,sizeof(time_string),"%Y-%m-%d %H:%M:%S",rectime);
//printf("date: %s \n",time_string);
//insert into record values(time, username, word);
sprintf(sql,"insert into record values('%s','%s','%s');",time_string, name, word);
if(sqlite3_exec(db,sql,NULL, NULL, &errmsg) != SQLITE_OK)
{
printf("sqlite_exec fail %s \n",errmsg);
exit(-1);
}
}
int history_callback(void* arg, int columns ,char** fvalue, char** fname)
{
//printf("history_callback begin \n");
MSG msg;
int * recvfd = (int *)arg;
//int recvfd = *(int *)arg;
// printf("fvalue[0]")
sprintf(msg.data,"%10s|%10s|%10s",fvalue[0],fvalue[1],fvalue[2]);
//printf("%s\n",msg.data);
if(send(*recvfd, &msg, sizeof(MSG), 0) < 0 )
{
perror("send fail");
exit(-1);
}
return 0;
}
void do_history(int* recvfd, sqlite3 * db, MSG * pmsg)
{
printf("do_history : server\n");
char sql[256];
sprintf(sql,"select * from record where username='%s';",pmsg->name);
char * errmsg;
//select * from record
if((sqlite3_exec(db, sql, history_callback, (void *)recvfd, &errmsg)) != SQLITE_OK)
{
printf("sqlite_exec fail %s \n",errmsg);
exit(-1);
}
// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
strcpy(pmsg->data,"query_over");
send(*recvfd, pmsg, sizeof(MSG), 0);
}
void cil_data_handle(int signum)
{
if(signum == SIGCHLD)
{
waitpid(-1,NULL,WNOHANG);
}
}
效果展示
一级菜单
查询功能
历史记录