网络编程---TCP电子词典

创作本文目的:记录自己的学习历程


一、实现TCP电子词典

1.要求

项目要求:

  1. 登录注册功能,不能重复登录,重复注册
  2. 单词查询功能
  3. 历史记录功能,存储单词,意思,以及查询时间
  4. 基于TCP,支持多客户端连接
  5. 采用数据库保存用户信息与历史记录
  6. 将dict.txt的数据导入到数据库中保存。
  7. 按下ctrl+c退出客户端后,注销该客户端的登录信息

格式要求:

  1. main函数只跑逻辑,不允许跑功能代码
  2. 功能代码封装成函数

2.流程图

在这里插入图片描述

3.代码

服务器

#include "function.h"

typedef void (*sighandler_t)(int);

void handler(int sig)
{
   
	//回收僵尸进程
	while(waitpid(-1, NULL, WNOHANG) > 0);
}

int main(int argc, const char *argv[])
{
   
	int newfd = 0;
	pid_t pid = 0;
	sqlite3 *db=init_db();

	//数据库起始化
	if(NULL==db)
	{
   
		fprintf(stderr,"起始化失败\n");
		return -1;
	}
	

	//捕获17号信号 SIGCHLD
	sighandler_t s = signal(17, handler);
	if(SIG_ERR == s)
	{
   
		ERR_MSG("signal");
		return -1;
	}

	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
   
		ERR_MSG("socket");
		return -1;
	}

	//允许端口快速重用
	int reuse = 1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
	{
   
		ERR_MSG("setsocket");
		return -1;
	}

	//填写服务器地址信息结构体
	struct sockaddr_in ser;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(PORT);
	ser.sin_addr.s_addr = inet_addr(IP);

	//绑定
	if(bind(sfd,(struct sockaddr *)&ser,sizeof(ser))!=0)
	{
   
		ERR_MSG("bind");
		return -1;
	}

	//监听
	if(listen(sfd,10)!=0)
	{
   
		ERR_MSG("listen");
		return -1;
	}

	//保存客户端的地址信息结构体
	struct sockaddr_in cli;
	socklen_t addrlen = sizeof(cli);

	while(1)
	{
   
		//父进程
		//生成通信的文件描述符
		int newfd = accept(sfd,(struct sockaddr *)&cli,&addrlen);
		if(newfd<0)
		{
   
			ERR_MSG("accept");
			return -1;
		}
		pid = fork();
		if(pid>0)
		{
   
			//节省父进程文件描述符
			close(newfd);
		}
		else if(0==pid)
		{
   
			//节省子进程文件描述符
			close(sfd);

			//与客户端交互函数
			interact(newfd,db,cli);
	
			//交互结束就关闭
			close(newfd);
			exit(0);
		}
		else 
		{
   
			ERR_MSG("fork");
			return -1;
		}
	}

	//关闭数据库
	if(sqlite3_close(db)!=SQLITE_OK)
	{
   
		fprintf(stderr,"__%d__ sqlite3_close:%s\n",__LINE__,sqlite3_errmsg(db));
	}

	//关闭文件描述符
	close(sfd);

	return 0;
}

客户端

#include "function.h"

int main(int argc, const char *argv[])
{
   
	char choose = 0;

	//创建流式套接字
	int sfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sfd < 0)
	{
   
		ERR_MSG("socket");
		return -1;
	}

	//填充要连接的服务器的地址信息结构体
	struct sockaddr_in ser;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(PORT);
	ser.sin_addr.s_addr = inet_addr(IP);

	//连接服务器 connect
	if(connect(sfd, (struct sockaddr*)&ser, sizeof(ser)) < 0)
	{
   
		ERR_MSG("connect");
		return -1;
	}
	//选择界面
	while(1)
	{
   
		system("clear");
		printf("-----------------------\n");
		printf("--------1. 注册--------\n");
		printf("--------2. 登录--------\n");
		printf("--------3. 退出--------\n");
		printf("-----------------------\n");
		printf("请输入选项>>>");
		choose = getchar();
		while(getchar()!=10);
		switch(choose)
		{
   
		case '1':
			//注册函数
			my_register(sfd);
			break;
		case '2':
			//登录函数
			login(sfd);
			break;
		case '3':
			//退出
			goto END;
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
		printf("输入任意字符清屏>>>");
		while(getchar()!=10);

	}
END:

	//关闭套接字
	close(sfd);

	return 0;
}

功能代码

#include "function.h"

//数据库起始化
sqlite3 *init_db()
{
   
	sqlite3 *db=NULL;
	//打开数据库
	if(sqlite3_open("./dict.db", &db) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ sqlite3_open:%s\n", __LINE__,
				sqlite3_errmsg(db));
		return NULL;
	}
	//创建账户信息表格
	char sql[400] = "create table if not exists user (username char primary key,password char,state int)";
	char* errmsg = NULL;
	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__,errmsg);
		return NULL;
	}
	//创建历史记录表格
	sprintf(sql,"create table if not exists record (username char,word char,mean char,time char)");
	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__,errmsg);
		return NULL;
	}
	//导入dict.txt文本到数据库
	if(import_dict(db)!=0)
	{
   
		fprintf(stderr,"__%d__ 词典导入失败\n",__LINE__);
		return NULL;
	}

	//用户表全部更新为下线状态
	sprintf(sql, "update user set state=%d where state=%d;",NOTLOGIN,LOGIN);
	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ error_code:%d sqlite3_exec:%s\n", __LINE__,sqlite3_errcode(db),errmsg);
		return NULL;
	}

	printf("数据库起始化完成\n");

	return db;
}

//导入dict.txt文本到数据库
int import_dict(sqlite3* db)
{
   
	char sql[200] = "create table if not exists dict (word char, mean char)";
	char* errmsg = NULL;
	//创建表格
	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__,errmsg);
		return -1;
	}

	char **pres = NULL;    //存储查询结果的首地址
	int row=0;             //查询结果的行数
	int column=0;          //查询结果的列数
	sprintf(sql,"select * from dict;");
	if(sqlite3_get_table(db,sql,&pres,&row,&column,&errmsg)!=SQLITE_OK)
	{
   
		fprintf(stderr,"__%d__ sqlite3_get_table:%s\n",__LINE__,errmsg);
		return -1;
	}
	if(row>7000)
	{
   
		printf("词典已导入\n");
		return 0;
	}

	//创建表格
	if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
	{
   
		fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__,errmsg);
		return -1;
	}
	//打开文件
	FILE* fp = fopen("./dict.txt", "r");
	if(NULL == fp)
	{
   
		ERR_MSG("fopen");
		return -1;
	}
	//循环读取一行,直到读取完毕为止
	char buf[300] = "";
	char word[50]="", mean[300]="";
	int i = 0;
	while(fgets(buf, sizeof(buf)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值