基于Linux系统开发在线词典

Linux开发词典
做了一个小级别的实验项目,对之前所学过的知识有个综合性的总结。在线词典实验涉及有,Linux C语言的开发、网络套接字编程、多进程开发、sqlite3数据库接口调用、文件读写等操作,make编译及Makefile文件的编写。。

项目介绍

项目总体划分为客户端、和服务端两个部分。客户端(也是APP)一方面为使用的用户提供简单的注册、登录、查询等操作,另一方面负责与服务端进行TCP通信,向服务器发送请求。而真正提供服务的是服务端进程,它不仅能和数据库进行交互,而且要接收用户的请求,把服务提供给用户。

用户通过客户端程序访问部署在服务端的词典,具体可以实现的功能有:

注册用户/用户登录
用户查询词典(查询英文单词的解释信息)
用户查询自己的历史查询记录

具体设计流程

运行客户端,首先出现一个主菜单,用户输入‘1’为注册,‘2‘为登录,‘3’为退出。当用户输入‘2’,登录成功后,又会进入二级服务菜单。这时用户输入‘1’为查询单词,‘2‘为查询历史,‘3’为退出。

以上是客户端应用的实现,底层调用的网络接口免不了要跟服务端交互。至于请求的类型和数据,需要我们自己根据需求来设计,与服务端统一保持一致即可。

服务端,主要负责接收客户端的请求信息,另一方面与数据库(调用相关函数创建)进行交互。由于客户端不只一个,我们用多进程的方法来处理多个客户端的请求;分析不同的请求信息,比如查询历史,服务端接收到这一命令后,就向数据库的历史记录表查询相关信息,再将结果处理,再返回到客户端。

虽然可以将词典的内容做成一个数据表,载入数据库,这样查询起来也十分方便,但是太过麻烦。所以我们将单词与相关解释信息放到一个文件中,查询单词时,到这个文件中匹配信息即可。

代码实现(代码量较大,只展示部分)

共用头文件 common.h

#ifndef __COMMON_H__
#define __COMMON_H__
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
 
#define   N  32
typedef struct {
	int type;
	char name[N];
	char data[256];
}MSG;
 
#define  R  1   // user - register
#define  L  2   // user - login
#define  Q  3   // user - query
#define  H  4   // user - history
 
#define  DATABASE  "my.db" //创建的数据库
 
 
#define SERADDR "127.0.0.1"   //这里笔者偷个懒,使用网络回送地址,就不进行远程通信了
#define SERPORT 5001          //服务端占用 5001 这个端口
 
#endif

客户端文件 client.c

#include "common.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);				//二级子菜单
 
 
 
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("* 1.register          2.login              3.quit               *\n");
		printf("*****************************************************************\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("Invalid data cmd.\n");
		}
 
 
	}
	return 0;
}
 
int SubMenu(int sockfd)
{
	int n;
	MSG  msg;
 
	while(1)
	{
		printf("-----------------------------------------------------\n");
		printf("- 1.query_word   2.history_record   3.quit          -\n");
		printf("-----------------------------------------------------\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;
}
 
 
///
//省略一堆底层函数实现
//

服务端文件 server.c

#include "common.h"
 
 
 
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 history_callback(void* arg,int f_num,char** f_value,char** f_name);//查询历史函数使用的回调
int do_searchword(int acceptfd, MSG *msg, char word[]);//查询单词函数的回调
int get_date(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);
 
	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); //处理僵尸进程
	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)  
		{//son process
			close(sockfd);
			do_client(acceptfd, db);
 
		}
		else  
		{//father process
 
			close(acceptfd);
		}
	}
 
	return 0;
}
 
 
int do_client(int acceptfd, sqlite3 *db)
{
	MSG msg;
	while(recv(acceptfd, &msg, sizeof(msg), 0) > 0)
	{
		printf("type:%d\n", msg.type);
		switch(msg.type)
		{
		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("client exit.\n");
	close(acceptfd);
	exit(0);
 
	return 0;
}
 
 
///
//省略一堆底层函数实现
//

实验结果展示

————————————————
版权声明:本文为CSDN博主「王建峰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/feit2417/java/article/details/82724385

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值