基于TCP的简易电子词典

头文件:

#ifndef __HEAD_H__
#define __HEAD_H__
 
#include 
 
#define   N  32
typedef struct {
	int type;
	char name[N];
	char data[256];
	int option;
	int flag;
}MSG;
 
#define  R  1   // 用户注册
#define  L  2   // 用户登录
#define  Q  3   // 查询单词
#define  H  4   // 历史记录
 
#define  DATABASE  "my.db" //创建的数据库
 
 
#define SERADDR "192.168.114.156"   
#define SERPORT 8888          
 
#endif

服务器:

#include "head.h"
 
void init_sql(sqlite3 *db);
int do_client(int acceptfd, sqlite3 *db); //客户端请求入口
void do_register(int acceptfd, MSG *msg, sqlite3 *db);//注册用户实现
int do_login(int acceptfd, MSG *msg, sqlite3 *db);//用户登录实现
int do_query(int acceptfd, MSG *msg, sqlite3 *db);//用户查询单词实现
int do_history(int acceptfd, MSG *msg, sqlite3 *db);//查询历史记录
int get_data(char *date);//获取时间
 
int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in  serveraddr;
	int acceptfd;
 
	sqlite3 *db;
	pid_t pid;
	//打开数据库
	if(sqlite3_open(DATABASE, &db) != SQLITE_OK)
	{
		printf("%s\n", sqlite3_errmsg(db));
		return -1;
	}
	else
	{
		printf("open DATABASE success.\n");
	}
 	//套接字
	if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
	{
		perror("fail to socket.\n");
		return -1;
	}
 
	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(SERADDR);
	serveraddr.sin_port = htons(SERPORT);
	int reuse = 1;
	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
	{
		perror("setsockopt");
		return -1;
	} 
	//绑定
	if(bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		perror("fail to bind.\n");
		return -1;
	}
 	//监听
	if(listen(sockfd, 5) < 0)
	{
		printf("fail to listen.\n");
		return -1;
	}
 
	signal(SIGCHLD, SIG_IGN); //处理僵尸进程
	if (sqlite3_open("./my.db", &db) != SQLITE_OK)
	{
		fprintf(stderr, "line:%d sqlite_open:%s\n", __LINE__, sqlite3_errmsg(db));
		return -1;
	}
	init_sql(db);
	struct sockaddr_in cin;
	socklen_t cin_len = sizeof(cin);
 
	while(1)
	{
		//接收
		if((acceptfd = accept(sockfd, NULL, NULL)) < 0)
		{
			perror("fail to accept");
			return -1;
		}
		//创建子进程
		if((pid = fork()) < 0)
		{
			perror("fail to fork");
			return -1;
		}
		//子进程
		else if(pid == 0)  
		{
			close(sockfd);
			do_client(acceptfd, db);
 
		}
		//父进程
		else  
		{
			close(acceptfd);
		}
	}
 
	return 0;
}
 
//客户端请求入口 
int do_client(int acceptfd, sqlite3 *db)
{
	MSG msg;
	while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
	{
			switch(msg.option)
		{
		case R:
			do_register(acceptfd, &msg, db);
			break;
		case L:
			do_login(acceptfd, &msg, db);
			break;
		case Q:
			do_query(acceptfd, &msg, db);
			break;
		case H:
			do_history(acceptfd, &msg, db);
			break;  
		default:
			printf("Invalid data msg.\n");
		}
 
	}
 
	printf("用户已退出\n");
	close(acceptfd);
	exit(0);
 
	return 0;
}
//数据库操作
void init_sql(sqlite3 *db)
{
 
	printf("正在初始化...\n");
	//创建表
 
	char sql[256] = "";
	char *errmsg = NULL;
	strcpy(sql, "create table if not exists usr (name char PRIMARY KEY,passwd char,status char);");
	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_exec error:%s\n", errmsg);
		return;
	}
	strcpy(sql, "create table if not exists log (name char,word char,explain char,time char);");
	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_exec error:%s\n", errmsg);
		return;
	}
	strcpy(sql, "create table if not exists dict (Word char,Explain char);");
	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_exec error:%s\n", errmsg);
		return;
	}
	//判断词库存不存在
	char **result = NULL;
	int rows = 1;
	int columns = 0;
	// char sql[128] = "select * from stu";
	strcpy(sql, "select * from dict");
	if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
		return;
	}
	sqlite3_free_table(result);
	if (rows < 7987)
	{
		printf("正在导入词库...\n");
		FILE *fp = fopen("./dict.txt", "r");
		if (NULL == fp)
		{
			perror("fopen");
			return;
		}
		char buff[300];
		char Word[64];
		char Explain[256];
 
		char *p = NULL;
 
		while (NULL != fgets(buff, sizeof(buff), fp))
		{
			p = buff;
			while (1)
			{
				if (*p != ' ' || (*p == ' ' && *(p + 1) != ' '))
					p++;
				else
					break;
			}
			*p = '\0';
			p++;
			//获取单词
			strcpy(Word, buff);
			//跳过空格
			while (*p == ' ')
			{
				p++;
			}
			//截取解释
			strcpy(Explain, p);
			sprintf(sql, "insert into dict values(\"%s\",\"%s\")", Word, Explain);
			if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
			{
				printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
				return;
			}
		}
	}
	printf("单词库导入成功\n");
}
void do_register(int acceptfd, MSG *msg, sqlite3 *db)//注册用户实现
{
	char sql[512] = {0};
	char *errmsg;
	sprintf(sql, "insert into usr values(\"%s\",\"%s\",'no');", msg->name, msg->data);
	// name为主键,插入失败则用户名已经存在
	if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
		// printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
		sprintf(msg->data, "用户名 %s 已存在!!", msg->name);
	}
	else
	{   printf("新用户:%s 已注册\n",msg->name);
		strcpy(msg->data, "注册成功!!");
	}
	send(acceptfd, msg, sizeof(MSG), 0);
	return;
}
int do_login(int acceptfd, MSG *msg, sqlite3 *db)//用户登录实现
{
	char sql[512] = {0};
	char *errmsg, **result;
	int rows, columns;
 
	//通过sqlite3_get_table函数查询记录是否存在
	sprintf(sql, "select * from usr where name = '%s' and passwd = '%s'", msg->name, msg->data);
	if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
	}
	//通过row参数判断是否能够查询到疾记录,如果值为0,则查询不到,如果值为非0,则查询到
	if (rows == 0)
	{
		strcpy(msg->data, "登录失败,用户名或密码错误");
		msg->flag = 0; //失败
	}
	else
	{
		strcpy(msg->data, "登录成功");
		sprintf(sql, "update usr set status = 'yes' where name = '%s'", msg->name); //登录之后状态设置为yes;
		if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
		{
			printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
		}
		msg->flag = 1; //成功
		printf("用户%s已登录\n", msg->name);
	}
 
	send(acceptfd, msg, sizeof(MSG), 0);
 
	return 0;
}
int do_query(int acceptfd, MSG *msg, sqlite3 *db)//用户查询单词实现
{
	char sql[512] = "", *errmsg = NULL;
	int found = 0;
	char date[128];
	char **result = NULL;
	int rows = 0;
	int columns = 0;
	sprintf(sql, "select * from dict where Word='%s'", msg->data);
	if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
		return -1;
	}
	if (0 == rows)//没有查到
	{
		strcpy(msg->data, "Not Found!!!");
		send(acceptfd, msg, sizeof(MSG), 0);
	}
	else
	{
		printf("%s\t\t%s\n", result[2], result[3]);
		strcpy(msg->data, result[3]);
		//如果执行成功,还需要保存历史记录
		//获取时间
		get_data(date);
		//通过sqlite3_exec函数插入数据
		bzero(sql, sizeof(sql));
		sprintf(sql, "insert into log values('%s', '%s', '%s', '%s')", msg->name, result[2], result[3], date);
		if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
		{
			printf("sqlite3_exec error:%s line=%d\n", errmsg, __LINE__);
		}
		printf("%s 查询成功\n",msg->name);
		send(acceptfd, msg, sizeof(MSG), 0);
	}
	return 0;
}
int do_history(int acceptfd, MSG *msg, sqlite3 *db)//查询历史记录
{
	char sql[512] = "", *errmsg = NULL;
	int found = 0;
	char info[512];
	char **result = NULL;
	int rows = 0;
	int columns = 0;
	printf("%s 正在查询记录...\n", msg->name);
	sprintf(sql, "select * from log where name='%s'", msg->name);
	if (sqlite3_get_table(db, sql, &result, &rows, &columns, &errmsg) != SQLITE_OK)
	{
		printf("sqlite3_get_table error:%s line=%d\n", errmsg, __LINE__);
		return -1;
	}
	//将记录逐条发送给客户端
	for (int i = 1; i <= rows; i++)
	{
		sprintf(info, "%s:\t%s\t%s\t%s\n", result[i * columns], result[i * columns + 1], result[i * columns + 2], result[i * columns + 3]);
		send(acceptfd, info, sizeof(info), 0);
	}
	strcpy(info, "已到末尾");
	send(acceptfd, info, sizeof(info), 0);
	return 1;
}

int get_data(char *date)//获取时间
{
	time_t t;
	struct tm *tp;
	time(&t);
	tp = localtime(&t);
	sprintf(date, "历史时间:%d-%02d-%02d %02d:%02d:%02d",
			1900 + tp->tm_year, 1 + tp->tm_mon, tp->tm_mday,
			tp->tm_hour, tp->tm_min, tp->tm_sec);
 
}

客户端:

#include "head.h"
 
 
int  do_register(int sockfd, MSG *msg);	//注册用户
int do_login(int sockfd, MSG *msg);		//用户登录
int do_query(int sockfd, MSG *msg);		//查询单词
int do_history(int sockfd, MSG *msg);	//查询历史
int SubMenu(int sockfd);				//查询界面
 
char name[20];
int flag=0; 
 
int main(int argc, const char *argv[])
{
	int sockfd;
	struct sockaddr_in  serveraddr;
	int n;
	MSG  msg;
 
	if((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
	{
		perror("fail to socket.\n");
		return -1;
	}
 
	bzero(&serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = inet_addr(SERADDR);
	serveraddr.sin_port = htons(SERPORT);
 
	if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
	{
		perror("fail to connect");
		return -1;
	}
 
	while(1)
	{
		printf("*****************************登录界面****************************\n");
		printf("**********************请输入序号进行对应操作*********************\n");
		printf("****************************1.注册*******************************\n");
		printf("****************************2.登录*******************************\n");
		printf("****************************3.退出*******************************\n");
		printf("请输入>>>");
 
		scanf("%d", &n);
		getchar();
 
		switch(n)
		{
		case 1:
			do_register(sockfd, &msg);
			break;
		case 2:
			if(do_login(sockfd, &msg) == 1)
			{
				SubMenu(sockfd);	
			}
			break;
		case 3:
			close(sockfd);
			exit(0);
			break;
		default:
			printf("输入不合法,请重新输入\n");
		}
 
 
	}
	return 0;
}
 
int SubMenu(int sockfd)
{
	int n;
	MSG  msg;
 
	while(1)
	{
		printf("*****************************查询界面****************************\n");
		printf("**********************请输入序号进行对应操作*********************\n");
		printf("**************************1.查询单词*****************************\n");
		printf("**************************2.查询历史记录*************************\n");
		printf("**************************3.退出*****************************\n");
		printf("请输入>>>");
		scanf("%d", &n);
		getchar();
 
		switch(n)
		{
		case 1:
			do_query(sockfd, &msg);
			break;
		case 2:
			do_history(sockfd, &msg);
			break;
		case 3:
			close(sockfd);
			exit(0);
			break;
		default :
			printf("Invalid data cmd.\n");
		}
 
	}
	return 0;
}
 
int  do_register(int sockfd, MSG *msg)	//注册用户
{
	msg->option = R;
	printf("请输入要注册的用户名>>>");
	scanf("%s", msg->name);
	while (getchar() != 10)
		;
	printf("请输入密码>>>");
	scanf("%s", msg->data);
	while (getchar() != 10)
		;
	//将用户名及密码发送给服务器,判断是否存在
	send(sockfd, msg, sizeof(MSG), 0);
	recv(sockfd, msg, sizeof(MSG), 0);
	//接收服务器发回来的消息来判断是否成功
	printf("Register: %s\n", msg->data);
	return 0;
}
int do_login(int sockfd, MSG *msg)		//用户登录
{
//设置操作码
    msg->option = L;
    //输入用户名
    printf("请输入用户名>>>");
    scanf("%s", msg->name);
    while (getchar() != 10)
        ;
    //输入密码
    printf("请输入密码>>>");
    scanf("%s", msg->data);
    while (getchar() != 10)
        ;
    //发送数据给服务器
    send(sockfd, msg, sizeof(MSG), 0);
    //接收服务器发送的数据
    recv(sockfd, msg, sizeof(MSG), 0);
 
    //判断是否登录成功
    printf("%s\n", msg->data);
    if (msg->flag == 0)
    {
        return 0;
    }
    else
    {
        strcpy(name, msg->name);
        return 1;
    }
}
int do_query(int sockfd, MSG *msg)		//查询单词
{
msg->option = Q;
    strcpy(msg->name, name);
    printf("-----------------------------单词查询中-----------------------------\n");
    while (1)
    {
        printf("请输入单词 (输入88退出): ");
        scanf("%s", msg->data);
        while (getchar() != 10)
            ;
        //如果输入的是#,返回
        if (strcmp(msg->data, "88") == 0)
        {
            break;
        }
 
        send(sockfd, msg, sizeof(MSG), 0);
 
        recv(sockfd, msg, sizeof(MSG), 0);
        printf("EXPLANTION %s\n", msg->data);
    }
    return 0;
}
int do_history(int sockfd, MSG *msg)	//查询历史
{
	 char info[512];
    msg->option = H;
    strcpy(msg->name, name);
    send(sockfd, msg, sizeof(MSG), 0);
    while (1)
    {
        recv(sockfd, info, sizeof(info), 0);
        printf("%s\n", info);
        if (0 == strcmp(info, "已到末尾"))
        {
            break;
        }
    }
    return 0;
 
}

你可能感兴趣的:(tcp/ip,数据库,网络协议,c语言)