在线词典项目实战

功能:基于网络编程和数据库实现在线词典功能,客户端可以注册,登入,查询历史信息等操作,服务器基于多进程实现多客户端的并发访问,并使用sqlite数据库实现对用户信息的管理。

在线词典项目实战_第1张图片

客户端程序

#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);
}



你可能感兴趣的:(多进程,网络编程,数据库)