C语言在线词典项目—Linux

C语言-在线词典项目

功能:基于Linux操作系统,网络编程和数据库实现在线词典功能,客户端可以注册,登入,查询历史信息等操作,服务器基于TCP,多进程实现多客户端的并发访问,并使用sqlite3数据库实现对用户信息的管理。
1.注册:若用户名已经注册过,重新注册
2.登录:用户名或密码错误需重新登录
3.查询:输入要查的单词,#键结束查询
4.历史:可以查询当前用户历史查找过的单词
5.退出:退出英英在线词典

C语言在线词典项目—Linux_第1张图片

客户端

#include
#include
#include
#include
#include

#include
#include
#include
#include

#define N 20
#define SIZE 256
#define R 1
#define L 2
#define H 3
#define Q 4

typedef struct
{
	int type;
	char name[N];
	char data[SIZE];
}MSG;
//用户注册
void do_register(int sockfd,MSG *pbuf)
{
	pbuf->type = R;
	printf("用户名:");
	scanf("%s",pbuf->name);
	printf("密  码:\033[8;33m");
	scanf("%s",pbuf->data);

	send(sockfd,pbuf,sizeof(MSG),0);
	recv(sockfd,pbuf,sizeof(MSG),0);
	printf("\033[0m %s\n",pbuf->data);
	sleep(1);
}
//用户登录
int do_login(int sockfd,MSG *pbuf)
{
	pbuf->type = L;
	printf("用户名:");
	scanf("%s",pbuf->name);
	printf("密  码:\033[8;33m");
	scanf("%s",pbuf->data);
	send(sockfd,pbuf,sizeof(MSG),0);

	recv(sockfd,pbuf,sizeof(MSG),0);
	if(pbuf->type == 8)
	{	
		printf("\033[0m %s\n",pbuf->data); 
		sleep(1);
		return 1;
	}
	else
	{
		printf("\033[0m %s\n",pbuf->data);
		return 0;
	}
}

//查找单词
void do_query(int sockfd,MSG *pbuf)
{
	pbuf->type = Q;
	printf("请输入你要查询的单词(#结束):");
	while(1)
	{
		scanf("%s",pbuf->data);
		getchar();
		if(strcmp(pbuf->data,"#")==0)
			break;
		send(sockfd,pbuf,sizeof(MSG),0);

		recv(sockfd,pbuf,sizeof(MSG),0);

		printf("╭( ′• o •′ )╭☞就是这个意思:%s\n",pbuf->data);
		sleep(1);
		printf("请输入你要查询的单词:");
	}
}

//查询历史单词
void do_history(int sockfd,MSG *pbuf)
{
	pbuf->type = H;
	send(sockfd,pbuf,sizeof(MSG),0);
	while(1)
	{
		recv(sockfd,pbuf,sizeof(MSG),0);
		if(pbuf->data[0] == '0')		//历史单词全部接受完成
			break;
		printf("%s\n",pbuf->data);
	}
	sleep(0.2);
}

//二级菜单
void menu_2(int sockfd,MSG *pbuf)
{
	while(1)
	{
		printf("\033[1;33m****************************************\n");//字体格式设置
		printf("*            欢迎使用电子词典          *\n");
		printf("****************************************\n");
		printf("*  1:查询单词  2:查询历史单词  3:退出  *\n");
		printf("****************************************\033[0m\n");//字体格式设置关闭
		printf("请选择:");
		scanf("%d",&pbuf->type);
		switch(pbuf->type)
		{
			case 1: 
				do_query(sockfd,pbuf);
				break;
			case 2:
				do_history(sockfd,pbuf);
				break;
			case 3:
				printf("      即将退出,欢迎您再次使用( ̄o ̄) . z Z\n");
				send(sockfd,pbuf,sizeof(MSG),0);
				sleep(1);
				close(sockfd);
				exit(-1);
			default:
				printf("\033[1;31m错误选项!\033[0m");
				break;
		}
	}
}

//一级菜单
void menu_1(int sockfd,MSG *pbuf)
{
	int mode;
	while(1)
	{
		printf("\033[1;36m****************************************\n");
		printf("*              电子词典项目            *\n");
		printf("****************************************\n");
		printf("*     1: 注册   2: 登录   3: 退出      *\n");
		printf("****************************************\033[0m\n");
		printf("请选择:");
		scanf("%d",&mode);

		switch(mode)
		{
		case 1: 
			do_register(sockfd,pbuf);
			break;
		case 2:
			while(do_login(sockfd,pbuf) != 1)
				continue;
			menu_2(sockfd,pbuf);
			break;
		case 3:
			printf("      即将退出,欢迎您再次使用( ̄o ̄) . z Z\n");
			sleep(1);
			close(sockfd);
			exit(-1);
		default:
				printf("\033[1;31m错误选项!\033[0m");
				break;
		}
	}
}

int main(int argc, const char *argv[])
{
	if ( argc != 3 )
	{
		printf("%s  \n",argv[0]);
		return -1;
	}
	
	int sockfd;
	if(( sockfd = socket(AF_INET, SOCK_STREAM, 0))<0)
	{
		perror("socket");
		return -1;
	}

	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	
	if( connect(sockfd, (struct sockaddr *)&serveraddr,sizeof(struct sockaddr)) < 0 )
	{
		perror("connect");
		return -1;
	}
	//与服务器连接完成后,进入功能模式选择菜单界面
	MSG buf;
	menu_1(sockfd,&buf);
	return 0;
}


服务器端

#include
#include
#include
#include
#include
#include
#include
#include

#define N 20
#define SIZE 256
#define R 1
#define L 2
#define H 3
#define Q 4

typedef struct
{
	int type;
	char name[N];
	char data[SIZE];
}msg_t;

sqlite3 *db;

void do_register(int connfd,msg_t *pbuf)	//注册功能	R
{
	char *errmsg,**result;
	int nrow=0,ncolumn;
	char sql[128]={0};
	sprintf (sql, "select * from usr where usr_name = '%s';",pbuf->name);

	if( sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg) != SQLITE_OK)
	{
		printf("error:%s\n",errmsg);
		exit(-1);
	}
	if(nrow > 0) 		//注册的用户名已经存在
	{
		sprintf(pbuf->data,"\n      用户名已经存在,请重新注册(̿▀̿ ̿Ĺ̯̿̿▀̿ ̿)\n");
		send(connfd, pbuf, sizeof(msg_t), 0);
	}
	else       			//用户名不存在,可以注册
	{
		sprintf(sql,"insert into usr values ('%s','%s');",pbuf->name,pbuf->data);
		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
		{
			perror("sqlite3_exec");
			printf("error:%s\n",errmsg);
			exit(-1);
		}
		sprintf(pbuf->data,"\n     %s,恭喜您,注册成功(。・ω・。)ノ♡",pbuf->name);	//返回注册成功信息给用户
		send(connfd,pbuf,sizeof(msg_t),0);
	}
}

void do_login(int connfd,msg_t *pbuf)		//登录	L
{
	char *errmsg;
	char sql[128]={0};
	int nrow=0,ncolumn=0;
	char **result;

	sprintf(sql,"select * from usr where usr_name = '%s' and usr_pwd = '%s';",pbuf->name,pbuf->data);
	if(sqlite3_get_table(db, sql,&result,&nrow,&ncolumn, &errmsg) != SQLITE_OK)
	{
		perror("sqlite3_get_table");
		printf("error:%s\n",sqlite3_errmsg(db));
		exit(-1);
	}
	if(nrow > 0)
	{
		sprintf(pbuf->data,"\n      %s,恭喜您,登录成功(。・ω・。)ノ♡\n",pbuf->name);
		pbuf->type = 8;
	}
	else
	{
		sprintf(pbuf->data,"\n  \033[1;31m用户名或密码错误,请重新输入o(# ̄▽ ̄)==O)) ̄0 ̄\")o金钢飞拳~!!\033[0m\n");
	}
	send(connfd,pbuf,sizeof(msg_t),0);
	//sqlite3_free_table(result);

}

//获取系统时间
char get_date(char *date)
{
	struct tm *tp = NULL;
	time_t rawtime;
	time(&rawtime);
	tp = localtime(&rawtime);
	sprintf(date,"%02d-%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);
}

void do_query(int connfd,msg_t *pbuf)	//请求	Q
{
	int ret;
	char line[200];	//用来保存读取的单词及解释
	char time[100];	//用来保存系统时间
	char *errmsg;
	char sql[128]={0};
	char word[200];
	strcpy(word,pbuf->data);
	int len = strlen(word);
	char *p = line + len;
	FILE * fp = fopen ("./dict.txt","r");
	if(fp == NULL)
	{
		perror("fopen failed");
		sprintf(pbuf->data,"抱歉,服务器打开词典文本失败 :(\n");
		send(connfd,pbuf,sizeof(msg_t),0);
		exit(-1);
	}

	while( fgets(line ,sizeof(line), fp) != NULL )
	{
		ret = strncmp(line,word,len);		
		if(ret == 0 && line[len] == ' ' )		//跳过单词及空格,直接定位到单词解释
		{
			while(*p == ' ')
				p++;
			strcpy(pbuf->data,p);
			send(connfd,pbuf,sizeof(msg_t),0);
			get_date(time);

			//将查找过的单词信息写进历史记录表中以备客户历史查找请求
			sprintf(sql,"insert into history_word values('%s','%s','%s');",pbuf->name,time,word);
			if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
			{
				perror("sqlite3_exec");
				printf("error:%s\n",errmsg);
				exit(-1);
			}
			fclose(fp);
			return (void)0;
		}
		else if(ret < 0)     
			continue;
		else   //遍历到对应单词位置仍未查到,不用再继续查找,跳出循环
			break;
	}
	sprintf(pbuf->data,"抱歉,没有找到该单词的意思(⍥(⍥(⍥(⍥(⍥;;) 惊呆惹\n");
	send(connfd,pbuf,sizeof(msg_t),0);
	fclose(fp);
}
//回调函数,每找到一条记录就执行一次该函数
int history_callback(void* arg, int f_column,char **f_value,char ** f_name)
{
	int i,connfd = *(int *)arg;
	msg_t pbuf;
	sprintf(pbuf.data,"%s , %s",f_value[1],f_value[2]);
	send(connfd,&pbuf,sizeof(pbuf),0);
	return 0;
}

int do_history(int connfd, msg_t *pbuf)	//历史查找	H
{
	char sqlstr[128]={0};
	char *errmsg;

	sprintf(sqlstr,"select * from history_word where usr_name = '%s';",pbuf->name);
	if(sqlite3_exec(db,sqlstr,history_callback,(void *)&connfd,&errmsg) != SQLITE_OK)
	{
		printf("error:%s\n",errmsg);
		return -1;
	}
	else
		printf("请求成功.\n");
	pbuf->data[0] = '0';
	send(connfd,pbuf,sizeof(msg_t),0);
	return 1;
}

//TCP	
int main(int argc, char *argv[])
{
	//参数1:./a.out  2:ip地址 3:端口
	if(argc<3)
	{
		printf("%s  \n",argv[0]);
		return -1;
	}
	//打开.db文件
	if((sqlite3_open("file.db",&db))<0)
	{
		perror("sqlite3_open");
		return -1;
	}
	//创建usr表保存用户名和密码
	char *errmsg;

	//创建套接字描述符  
	int lisenfd = socket(AF_INET,SOCK_STREAM,0);
	if(lisenfd < 0)
	{
		perror("socket");
		return -1;
	}
	//绑定
	struct  sockaddr_in serveraddr,clientaddr;
	int peerlen = sizeof(struct sockaddr);
	bzero(&serveraddr,sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
	
	if(bind(lisenfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr)) < 0 )
	{
		perror("bind");
		return -1;
	}
	
	//监听
	if(listen(lisenfd,10) < 0)
	{
		perror("listen");
		return -1;
	}

	msg_t buf;
	while(1)
	{
		//创建新的套接字描述符
		int connfd = accept(lisenfd,(struct sockaddr *)&serveraddr,&peerlen);
		if(connfd < 0)
		{
			perror("accept");
			return -1;
		}
		//创建子进程
		pid_t pid = fork();
		if( pid < 0 )
		{
			perror("fork");
			return -1;
		}
		else if(pid == 0)		//子进程
		{
			while(1)
			{
				if(recv(connfd,&buf,sizeof(buf),0)>0)
				{	
					printf("recv:%d:%s %s\n",buf.type,buf.name,buf.data);
					switch(buf.type)
					{
					case R: 
						do_register(connfd,&buf);
						break;
					case L:
						do_login(connfd,&buf);
						break;
					case Q: 
						do_query(connfd,&buf);
						break;
					case H: 
						do_history(connfd,&buf);
						break;
					default:
						break;
					}
				}
				else
				{
					perror("recv failed");
					exit(-1);
				}
			}
		}
		else                    //父进程退出
			close(connfd);
	}
	return 0;
}
sprintf(pbuf->data,"\n  \033[1;31m用户名或密码错误,请重新输入o(# ̄▽ ̄)==O)) ̄0 ̄\")o金钢飞拳~!!\033[0m\n");

(开始设置) \033[1;31m ————(关闭设置) \033[0m
设置字体格式:颜色、亮度、划线、隐藏……

效果展示:

C语言在线词典项目—Linux_第2张图片
C语言在线词典项目—Linux_第3张图片
C语言在线词典项目—Linux_第4张图片
C语言在线词典项目—Linux_第5张图片
C语言在线词典项目—Linux_第6张图片

你可能感兴趣的:(多进程,网络编程,sqlite,sqlite,多进程,1024程序员节)