基于Linux的小项目-在线词典

接触到的基于Linux的第一个实战小项目,在众多大牛的协助下完美实现。

在线词典功能的实现
1、用户的注册
2、用户登录
3、单词的查询
4、历史记录的查看
5、用户在登录后修改密码

头文件

#ifndef COMM_HH
#define COMM_HH

#include <stdio.h>	 
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <signal.h>
#include<time.h>

#define MSGTYPE_R  01 //用户注册
#define MSGTYPE_L  02 //用户登录
#define MSGTYPE_Q  03 //用户查询
#define MSGTYPE_H  04//用户历史记录
#define MSGTYPE_C  05//用户修改密码


#define DATABASE "lict.db"




typedef struct msg_struct{
	char cmd;		//1-register 2-log 3-exit 4-dic 5-history 6-passwd    12.服务器应答
	char name[32];
	char passwd[16];
	char new_passwd[16];
	char data[256];  
	int type;
	
	//以下是服务器的回应
	char ret;  //0-success  errno-失败原理
	char response[128];
}MSG_T;


#endif

客户端的实现

#include "comm.h"


int do_register(int socket_cli, MSG_T *msg)//客户端注册
{
	printf("用户注册注册中   ... \n");
	int ret;
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_R;//11;
	printf("请输入账号:"); scanf("%s", msg->name); getchar();
	printf(" ________________\n");
	printf("请输入密码:"); scanf("%s", msg->data); getchar();
	ret=send(socket_cli, msg, sizeof(MSG_T), 0);
	if (ret < 0){
		perror("send err");
		printf("注册信息发送失败.\n");
		return -1;
	}
	if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("注册失败.\n");
		return -1;
	}
	printf("%s\n", msg->data);
	return 1;
}
 

int do_login(int socket_cli, MSG_T *msg)// 登录, 必服务器返回 "OK" 才表示登录成功
{
	printf("正在登录 ...\n");
	
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_L;
	printf("  请输入账号:"); scanf("%s", msg->name); getchar();
	printf(" ---------------\n");
	printf("  请输入密码:"); scanf("%s", msg->data); getchar();
	
	if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("请重新登录\n");
		return -1;
	}
	
	if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("登录失败 !\n");
		return -1;
	}
	
	//登录成功
	if (strncmp(msg->data, "OK", 3) == 0)
	{
		printf("登录成功 ! \n");
		memset(msg, 0, sizeof(MSG_T));
		return 1;
	}
	else
	{
		printf("%s\n", msg->data);
	}
	
	return 0;
}


 int do_change(int socket_cli, MSG_T *msg)//修改用户密码
{
	printf("正在修改用户密码,务必确认本人操作   \n");
	int ret;
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_C;
	printf("请输入账号:"); scanf("%s", msg->name); getchar();
	printf(" ________________\n");
	printf("请输入密码:"); scanf("%s", msg->data); getchar();
	printf("\n");
	printf(" ________________\n");
	printf("请输入新密码:"); scanf("%s", msg->new_passwd); getchar();
	ret=send(socket_cli, msg, sizeof(MSG_T), 0);
	if (ret < 0){
		perror("send err");
		printf("修改请求发送失败.\n");
		return -1;
	}
	
	memset(msg, 0, sizeof(MSG_T));
	if (ret =0){
		perror("change err");
		printf("密码修改成功\n");
		return -1;
	}
	if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("修改失败.\n");
		return -1;
	}
	return 1;
}
 

int do_query(int socket_cli, MSG_T *msg) // 单词查询
{
	printf("查询中 ...\n");
	recv(socket_cli, msg, sizeof(MSG_T), 0);
	memset(msg, 0, sizeof(MSG_T));
	msg->type = MSGTYPE_Q;
	while(1)
	{
		printf("请输入单词:"); scanf("%s", msg->data); getchar();
		
		if (strncmp(msg->data, "*", 1) == 0)
			break;//退出
		
		if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
		{
			printf("发送失败\n");
			return -1;
		}
		memset(msg, 0, sizeof(MSG_T));
		if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
		{
			perror("接收失败");
			return -1;
		}
		printf("%s\n", msg->data);
	}
	return 1;
}
 

int do_history(int socket_cli, MSG_T *msg)  // 历史记录查询
{
	printf("...历史记录 ...\n");
	msg->type = MSGTYPE_H;
	//将消息发送给服务器
	if (send(socket_cli, msg, sizeof(MSG_T), 0) < 0)
	{
		printf("发送失败\n");
		return -1;
	}
	while(1)
	{
		if (recv(socket_cli, msg, sizeof(MSG_T), 0) < 0)
		{
			printf("接收失败\n");
			return -1;
		}
		if (msg->data[0] == '\0')
		    break;
    
		printf("%s\n", msg->data);
	}
	
	return 1;
 
}
 
int main(int argc, const char *argv[])
{
	struct sockaddr_in server_addr;
	int input_nbr;
	MSG_T send_msg;
	MSG_T                  msg;
	int socket_cli = socket(AF_INET,SOCK_STREAM, 0 );
	if(socket_cli <0){
		perror("create client socket err");
		return -3;
	}
	
	struct sockaddr_in  serv_addr;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(10050); 
	serv_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("192.168.17.129"); 
	int ret = connect(socket_cli,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(ret <0){
		perror("connect err");
		return -3;
	} 

	struct msg_struct cli_msg;
	
	while (1)
	{
		printf(" ______________________________________________\n");
		printf(" ______________________________________________\n");
		printf(" ________                               ________\n");
		printf(" ________  1.注册   2.登录    3.退出    ________\n");
		printf(" ______________________________________________\n");
		printf(" ______________________________________________\n");
		printf(" ______________________________________________\n");
		printf("\n");
		printf("请选择:");
		
		scanf("%d", &input_nbr);
		getchar();//回收垃圾字符
		
		switch (input_nbr)
		{
			case 1:
				do_register(socket_cli, &send_msg);
				break;
				
			case 2:
				if (do_login(socket_cli, &send_msg) ==1 )
				{
					goto _login;
				}
				break;
				
			case 3:
				close(socket_cli);
				exit(0);
				break;
			
			default:
				printf("Invalid data cmd. \n");
				break;
		}
	}
	
	
_login:
	while(1)//登录后的界面
	{
		printf(" ______________________________________________\n");
		printf(" ______________________________________________\n");
		printf("\n");
		printf("1.查询(*退出)  2.历史查询  3.退出   4.修改用户密码    \n");
		printf(" ______________________________________________\n");
		printf(" ______________________________________________\n");
		printf("\n");
		printf("请选择:");
		
		input_nbr = 0;
		scanf("%d", &input_nbr);
		getchar();
		switch (input_nbr)
		{
			case 1:
				do_query(socket_cli, &send_msg);
				break;
				
			case 2:
				do_history(socket_cli, &send_msg);
				break;
				
			case 3:
				close(socket_cli);
				exit(0);
				break;
			/*case 4:
				do_change(socket_cli, &send_msg);
				exit(0);
				break;*/
			
			default:
				printf("Invalid data cmd. \n");
				break;
		}
	}
	
	return 0;
	
}

服务器的实现

#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <pthread.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <signal.h>
#include<time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <sys/types.h>         
#include <sys/socket.h>



#include "comm.h"



static int cnt=1;
static int num=0;
static int s=0;
static int n=0;
static int ave;



struct thread_msg{
	int cli_socket;
	pthread_t tid;
	
};

sqlite3 *db = NULL;

int do_query(int socket_cli, MSG_T *msg, sqlite3 *db);
int do_login(int socket_cli, MSG_T *msg, sqlite3 *db);
int do_history(int socket_cli, MSG_T *msg, sqlite3 *db);
void get_date(char *data);

int print(void *para,int f_num,char **f_value,char **f_name)
{
	int i;
	if(cnt)
	{
		printf("--------------------------------------------------\n");
		cnt--;
		for(i=0;i<f_num;i++)
		{
			printf("%-12s",f_name[i]);
		}
		printf("\n");
		printf("--------------------------------------------------\n");
	}
	for(i=0;i<f_num;i++)
	{
		printf("%-12s",f_value[i]);
	}
	printf("\n");
	printf("--------------------------------------------------\n");

	return 0;
}
int do_register(int socket_cli, MSG_T *msg, sqlite3 *db) //用户注册
{
	char sql[128] = {0};
	int ret;
	snprintf(sql,sizeof(sql), "insert into user values('%s', '%s');", msg->name, msg->data );
	ret = sqlite3_exec(db,sql,print,NULL,NULL);
	if (ret!= SQLITE_OK){
		printf("%s\n",sqlite3_errmsg(db));
		memset(msg->data, 0, strlen(msg->data));
		snprintf(msg->data, sizeof (msg->data),"用户: %s 已存在!", msg->name);
	}
	else{
		printf( "客户(%s)注册成功\n",msg->name  );
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "register ok!");
	}
 
	//返回应答
	 ret=send(socket_cli, msg, sizeof(MSG_T), 0);
	 if(ret<0){
		printf("发送失败\n");
		return 0;
	}
	
	return 1;
}

void *serv_for_client(void *args)
{
	int ret;
	struct thread_msg *pmsg = args;
	int socketx = pmsg->cli_socket;
	
	struct msg_struct serv_msg;
	while(1){
		memset(&serv_msg,0,sizeof(serv_msg));
		ret = recv(socketx,&serv_msg,sizeof(serv_msg),0);
		if(ret<0){
			perror("recv err"); close(socketx); free(pmsg); return NULL;
		}else if(ret == 0){
			printf("serv found peer shutdwon\n"); close(socketx); free(pmsg); return NULL;
		}
		
		printf("%s->%d\n",__func__,__LINE__);
		
		switch(serv_msg.type)
		{
			case  01:             //MSGTYPE_R
				do_register(socketx, &serv_msg, db);
				break;
 
			case  02:                 //MSGTYPE_L:
				do_login(socketx, &serv_msg, db);
				break;
 
			case  03:               //MSGTYPE_Q:
				do_query(socketx, &serv_msg, db);
				break;
 
			case  04:                  //MSGTYPE_H:
				do_history(socketx, &serv_msg, db);
				break;
 
			default:
				printf("invalid data msg.\n");
		}
		
	
		ret = send(socketx,&serv_msg,sizeof(serv_msg),0);
		if(ret<0){
			perror("send err");  return NULL;
		}
	}
	/*while (recv(socketx, &serv_msg, sizeof(MSG_T), 0) > 0)
	{
		
	}
 
	printf("client exit.\n");
	close(socketx);
	exit(0);
 
	return 0;*/
	close(socketx);
	return NULL;
}

int do_login(int socket_cli, MSG_T *msg, sqlite3 *db)//用户登录
{
	char sql[128] = {0};
	char *errmsg = NULL, **result = NULL;
	int nrow, ncolumn,ret;
	snprintf(sql,sizeof(sql), "select * from user where name='%s' and passwd='%s';", msg->name, msg->data);
	ret=sqlite3_get_table(db, sql, &result, &nrow, &ncolumn, &errmsg) ;
	if (ret != SQLITE_OK){
		printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
	}else{
		printf("表格获取成功\n");
	}
	

 
	if (nrow == 1)//查询成功,数据库中拥有此用户
	{
		printf("用户:%s登录成功\n", msg->name);
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "OK");
	}
	else //用户名或密码错误
	{
		printf("用户:(%s) 登录失败! \n", msg->name);
		perror("login err");
		memset(msg->data, 0, strlen(msg->data));
		strcpy(msg->data, "账号或密码错误! \n");
	}
	//返回应答
	ret=send(socket_cli, msg, sizeof(MSG_T), 0);
	if (ret<0){
		perror("发送失败\n");
		return 0;
	}
	return 1;
}



int do_searchword(MSG_T *msg, char *word)//根据单词从dirt.txt文本中查找对应的注释信息
{
    FILE *fp = NULL;
    int word_len = strlen(word);
    char row_data[512] = {'\0'};
    int res = 0;
	int ret;
    char *p; //指向注释
    
    
     fp = fopen("dict.txt", "r")  ;//打开词典文件
    if (fp==NULL){
        perror("fail to open dict.txt.\n");
        return -1;
    }
 
    //打印客户端要查询的单词
    word_len = strlen(word);
    printf("%s, len = %d\n", word, word_len );
    while (fgets(row_data, 512, fp) != NULL)
    {
        res = strncmp(row_data, word, word_len);//每行对比前word_len个字节
        if (res != 0)
            continue;
        if (row_data[word_len] != ' ') //单词跟注释之间没有空格
            goto _end;
        p = row_data + word_len;// 找到了单词,跳过所有的空格
        while (*p == ' ')
        {
            p++;
        }
        strcpy(msg->data, p);
        fclose(fp);
        return 1;
    }
 
_end:
    fclose(fp);
    return 0; //文件对比完,单词未找到 
}


int do_query(int socket_cli, MSG_T *msg, sqlite3 *db)  // 单词查询
{
	char sql[128] = {0};
	char word[64] = {0};
	int found = 0;
    char date[128] = {0};
    char *errmsg;
	int ret;
    printf("\n");
    
    //单词查找
	strcpy(word, msg->data);
	//memset(msg->data, 0, strlen(msg->data));
	found = do_searchword(msg, word);//调用函数
 
	if (found == 1) {
	    get_date(date);//获取系统时间
	    snprintf(sql, 128,"insert into record values('%s', '%s', '%s')", msg->name, date, word);
	    ret=sqlite3_exec(db, sql,print, NULL, NULL );
	    if (ret != SQLITE_OK){
	        printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
	        return -1;
	    }
	}
    else if (found == 0)//没有找到
    {
        memset(msg->data, 0, strlen(msg->data));
        strcpy(msg->data, "单词未找到!\n");
    }
    else if (found == -1)//dict.txt代开失败
    {
        memset(msg->data, 0, strlen(msg->data));
        strcpy(msg->data, "打开 dict.txt.失败了");
    }
	send(socket_cli, msg, sizeof(MSG_T), 0);//将查询的结果发送给客户端
    return 0;
}



int history_callback(void* arg,int colCount,char** colValue,char** colName)// 得到查询结果,并且需要将历史记录发送给客户端
{
	int socketx;
	MSG_T msg;
	socketx = *((int *)arg);
	sprintf(msg.data, "%s , %s", colValue[1], colValue[2]);
	send(socketx, &msg, sizeof(MSG_T), 0);
	return 0;
}
 
int do_history(int socket_cli, MSG_T *msg, sqlite3 *db)// 历史记录查询
{
	char sql[128] = {0};
	char *errmsg;
	int ret;
 
    sprintf(sql, "select * from record where name = '%s'", msg->name);
	ret=sqlite3_exec(db, sql, history_callback,(void *)&socket_cli,NULL );
	if(ret!= SQLITE_OK){
		printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
	}
	else
	{
		printf("sqlite3 query record done.\n");
	}
	msg->data[0] = '\0';// 所有的记录查询发送完毕之后,给客户端发出一个结束信息
	ret = send(socket_cli, &msg, sizeof(MSG_T), 0);
	if(ret<0){
		perror("histroy send err");
		return -34;
	}
	
	return 0;
}

int do_change(int socket_cli, MSG_T *msg, sqlite3 *db) //修改用户密码
{
	char sql[128] = {0};
	int ret;
	char **pt=NULL;
	int nrow,ncolumn;
	snprintf(sql,sizeof(sql), "select from user where user=\'%S\' and passwd=\'%s\';", msg->name, msg->data );//查看数据库是否存在
	ret = sqlite3_get_table(db,sql,&pt,&norm,&ncolumn,NULL);
	if (ret){
		printf("gettabale err%s\n",sqlite3_errmsg(db));
		return -2;
	}
	
	if(nrow!=0)
	{
		char **pt=NULL;
		snprintf(sql,sizeof(sql), "updata user set passwd=\'%S\' and passwd=\'%s\';", msg->name, msg->data );//修改数据库中用户密码
		ret = sqlite3_get_table(db,sql,&pt,NULL,NULL,NULL);
		if (ret){
		printf("recv gettabale err%s\n",sqlite3_errmsg(db));
		return -2;
	}
	printf("密码修改成功");
	strcpy(msg->data, "修改成功!");
	ret = send(socket_cli, &msg, sizeof(MSG_T), 0);
	if(ret<0){
		perror("change send err");
		return -34;
	}
	}
	else{
		strcpy(msg->data, "输入有误!"); 
		ret=send(socket_cli, msg, sizeof(MSG_T), 0);
		if(ret<0){
		perror("change send err");
		return -34;
		memset(msg->data, 0, strlen(msg->data));
	}
 
	//返回应答
	
	 if(ret<0){
		printf("发送失败\n");
		return 0;
	}
	
	return 1;
}

void get_date(char *data)//获取系统时间
{
    time_t rowtime;
    struct tm *info;
    time(&rowtime);
    info = localtime(&rowtime);
    sprintf(data, "%d-%d-%d %d:%d:%d", info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec);                                  
    printf("get date is : %s\n", data);                                   
}



int main(int argc, const char *argv[])
{
	int ret;
	int socket_cli ;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(client_addr);

	char sql[128] = {0};
	pid_t pid;
	char ipv4_addr[16];

	/*********************数据库操作*********************/
	ret = sqlite3_open("./dict.db",&db);
	if(ret)
	{
		printf("sqlite3_open():%s\n",sqlite3_errmsg(db));
		exit(-1);
	}
	printf("sqlite3 open %s success.\n", DATABASE);
	//snprintf(sql,128, "");
	sqlite3_exec(db, sql, print ,NULL, NULL );
	if(ret != SQLITE_OK){
		printf("sqlite3_exec():%s\n",sqlite3_errmsg(db));
		return -1;
	}
	memset(sql, 0, sizeof(sql));
	sprintf(sql,  "    "   );
	
	ret=sqlite3_exec(db, sql, print , NULL, NULL  );//打开记录表
	if (ret != SQLITE_OK){
		printf("%s\n", sqlite3_errmsg(db));
		return -1; 
	}
	
	 /*********************网络通信*********************/
	int main_socket=socket(AF_INET,SOCK_STREAM,0);
	if(main_socket<0){
		perror("crreat main_socket err");
		return -5;
	}
	
	int enable=1;
	setsockopt(main_socket,SOL_SOCKET,SO_REUSEADDR,&enable,sizeof(enable));
	
	
	
	
	struct sockaddr_in serv_addr;
	serv_addr.sin_family=AF_INET;	
	serv_addr.sin_port=htons(10050);
	serv_addr.sin_addr.s_addr=INADDR_ANY;
	

	ret=bind(main_socket,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
	if(ret<0){
		perror("bind err");
		return -15;
	}
	ret = listen(main_socket,5);
	if(ret<0){
		perror("listen err");
		return -3;
	}
	
	struct sockaddr_in cli_addr;
	 addrlen=sizeof(cli_addr);
	struct thread_msg*pmsg=NULL;
	int socket_new;
    int cli_socket1;
loop:
	    cli_socket1=accept(main_socket,(struct sockaddr*)&cli_addr,&addrlen);
		if(cli_socket1<0){
		perror("accept err");
		return -5;
	}
	
	pmsg=malloc(sizeof(*pmsg));
	pmsg->cli_socket=cli_socket1;
	pthread_create( &pmsg->tid,NULL,serv_for_client, pmsg );
	goto loop;
	
	close(main_socket);
	return 0;
}


运行结果

服务器:
请添加图片描述

客户端:
在这里插入图片描述
在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小镇春风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值