电子词典项目

news2024/11/15 15:44:10

16. 电子词典项目需求

项目要求:

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

格式要求:

  1. main函数只跑逻辑,不允许跑功能代码
  2. 功能代码封装成函数
  1. 先分析需求
  2. 将上述需求用流程图画出来
  3. 根据流程图搭建代码框架
  4. 一个功能一个功能实现

 流程图:

http://t.csdn.cn/ScQSW

网络编程电子词典项目:

目录

项目要求:

格式要求:

 流程图:

服务器代码

客户端

实现效果

服务器代码

头文件

#ifndef __FUNC_H__          
#define __FUNC_H__          
#include <sqlite3.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/wait.h>
#include <stdlib.h>    
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#define PORT 6666              
#define IP "192.168.100.17"        
typedef void (*sighandler_t)(int);
#define ERR_MSG(msg) do{\
	fprintf(stderr,"line:__%d__\n",__LINE__);\
	perror(msg);\
}while(0)    

struct msg{                          
    char type;             //消息类型
    char name[128];    //名字        
    char password[128];   //密码     
    char word[128];       //单词     
    char trans[128];      //翻译     
    char time[256];       //时间     
}sermsg;                             
                                   
sqlite3* sqlite3_database();  //创建数据库表
int cli_net();            //创建套接字.链接客户端.绑定信息结构体
int sqlite3_close(sqlite3* db);   //关闭数据库
int sqlite3_word(sqlite3* db);  //导入单词函数
int sqlite3_worddelete(sqlite3 *db);   //删除单词表函数
int ser_recv(int newfd,struct sockaddr_in cin);  //接收函数
int do_login(int newfd);   //登录函数
int do_register(int newfd);   //注册函数
int do_find(int newfd);       //查询单词
int do_history(int newfd);     //查询历史记录
int do_quit(int newfd);  //退出
void handler(int sig);    //捕获僵尸进程
              
#endif    

功能文件

#include "01_serfunc.h"

sqlite3 *db=NULL;
char *errmsg=NULL;

sqlite3* sqlite3_database()
{
	//创建并打开一个数据库
	if(sqlite3_open("./word.db",&db)!=SQLITE_OK)
	{
		fprintf(stderr,"line:%d sqlite3_open failed:%d:%s\n",\
				__LINE__,sqlite3_errcode(db),sqlite3_errmsg(db));
		return NULL;
	}
	printf("sqlite3_open success\n");
	//删除单词表
	sqlite3_worddelete(db);
	//创建一张表格,数据库中sql怎么写就怎么写
	char sql[128]="create table if not exists wordbase(word char,explain char);";


	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
		return NULL;
	}
	printf("table stu create success\n");
	//创建一张表格 用于保存用户注册信息
	bzero(sql,sizeof(sql));
	sprintf(sql,"create table if not exists userbase(user char primary key,password char);");

	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
		return NULL;
	}
	printf("table userbase create success\n");
	//创建一张表格 用于存储用户登录信息
	bzero(sql,sizeof(sql));
	sprintf(sql,"create table if not exists recordbase(user char primary key);");

	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
		return NULL;
	}
	printf("table recordbase create success\n");


	//创建一张表格 用于存储用户历史查询信息                                              
	bzero(sql,sizeof(sql));                                                          
	sprintf(sql,"create table if not exists historybase(user char,word char,trans char,time char);");

	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)                            
	{                                                                                
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);                 
		return NULL;                                                                    
	}                                                                                
	printf("table historybase create success\n");
	//导入单词函数
	sqlite3_word(db);
	return db;

}
int sqlite3_close(sqlite3* db)   //关闭数据库
{
	//关闭数据库    
	if(sqlite3_close(db)!=SQLITE_OK)
	{
		fprintf(stderr,"line:%d sqlite3_close failed:%d:%s\n",\
				__LINE__,sqlite3_errcode(db),sqlite3_errmsg(db));
		return-1;
	}
	return 0;
}
int sqlite3_word(sqlite3 *db)  //导入单词函数
{
	//打开一个文件
	FILE *fd=fopen("./dict.txt","r");
	if(NULL==fd)
	{
		perror("fopen");
		return -1;
	}
	printf("电子词典正在导入请稍后>>>\n");
	//指定的文件中格式化获取数据
	//存储每一行数据
	char buf[512]="";
	char get_word[128]="";
	char get_explain[128]="";
	char sql[128]="";
	char *errmsg=NULL;
	//循环读取每一行内容
	while(1)
	{
		bzero(get_word,sizeof(get_word));
		bzero(get_explain,sizeof(get_explain));

		if(fgets(buf,sizeof(buf),fd)==NULL)
		{                                                                                               
			printf("单词导入完毕\n");
			return -1;
		}
		buf[strlen(buf)-1]='\0';
		for(int i=0;i<buf[i+2] ;i++)
		{
			if(buf[i]!=' ' && buf[i+1]==' ' && buf[i+2]==' ')
			{
				strncpy(get_word,buf,i+1);
			}
			else if(buf[i]==' ' && buf[i+1]==' ' && buf[i+2]!=' ')
			{
				strcpy(get_explain,buf+i+2);
				break;
			}
		}
		bzero(sql,sizeof(sql));
		sprintf(sql,"insert into wordbase values(\"%s\",\"%s\");",get_word,get_explain);

		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
		{
			fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
			return-1;
		}
	}
	//关闭文件描述符
	fclose(fd);
	return 0;
}
int sqlite3_worddelete(sqlite3 *db)   //删除单词表函数
{
	char sql[128]="drop table wordbase;";
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)                            
	{                                                                                
		//	fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);                 
		return-1;                                                                    
	}                                                                                
	printf("worddelete success\n");
	return 0;
}
int ser_recv(int fd,struct sockaddr_in cin) //接收函数
{
	int newfd=fd;
	ssize_t res=0;
	while(1)
	{
		//bzero(&sermsg,sizeof(sermsg));
		res=recv(newfd,&sermsg,sizeof(sermsg),0);
		struct msg sermsg1;
		strcpy(sermsg1.name,sermsg.name);
		printf("%s\n",sermsg1.name);

		if(res<0)
		{
			return -1;
		}
		else if(0==res)
		{
			fprintf(stderr,"[%s:%d]newfd = %d 客户端下线\n",\
					inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
			//删除登录信息
			char sql[521];                                              
			char *errmsg=NULL;                                          
			sprintf(sql,"delete from recordbase where user=\"%s\";",sermsg1.name);                       
			//printf("%s\n",sql);
			if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)       
			{                                                   
				fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
				return 0;
			}

			return 0;

		}
		char choose=sermsg.type;	
		switch(choose)
		{
		case '1':  //注册
			do_register(newfd);
			break;
		case '2':   //登录
			do_login(newfd);
			break;
		case '4':  //查询
			do_find(newfd);
			break;
		case '5':  //历史记录
			do_history(newfd);     //查询历史记录
			break;
		case '6':  //退出
			do_quit(newfd);
			break;
		}
	}
	return 0;
}
//捕获僵尸进程
void handler(int sig)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
    return ;
}

int cli_net()//创建套接字.链接客户端.绑定信息结构体
{
	//创建流式套接字
	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("setsockopt");
		return -1;
	}
	printf("允许端口快速重用\n");
	//填充地址信息结构体
	struct sockaddr_in sin; //定义结构体变量
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);
	//绑定信息结构体
	if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
	{                                                                                
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success\n");
	//将套接字设置为监听状态
	if(listen(sfd,5)<0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success\n");
	return sfd;
}
int do_quit(int newfd)
{
	//删除登录信息                                                         
	char sql[256];                                                         
	char *errmsg=NULL;                                                     
	sprintf(sql,"delete from recordbase where user=\"%s\";",sermsg.name);           
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)                  
	{                                                                      
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);       
		return 0;                                                          
	}                                                                      
	return 0;                                                              
}
int do_history(int newfd)    //查询历史记录
{
	//将数据包发送给客户端  根据登录名进行遍历查找记录表
	char sql[256]="";
	sprintf(sql,"select *from historybase where user=\"%s\";",sermsg.name);
	char **pres = NULL;   //存储结果
	int row, column;  //查询到的结果的行数;查询到的结果的列数
	char* errmsg = NULL;

	if(sqlite3_get_table(db, sql, &pres, &row, &column, &errmsg) != SQLITE_OK)
	{
		fprintf(stderr, "line:%d sqlite3_get_table:%s\n", __LINE__, errmsg);
		return -1;
	}
	printf("row=%d column=%d\n", row, column);   //打印行和列
	bzero(sermsg.name,sizeof(sermsg.name));
	bzero(sermsg.word,sizeof(sermsg.word));
	bzero(sermsg.trans,sizeof(sermsg.trans));
	bzero(sermsg.time,sizeof(sermsg.time));

	int i=0;
	for(i=0; i<(row+1)*column; i++)
	{
		if(i%column == column-4)
			sprintf(sermsg.name,"%s",pres[i]);
		else if(i%column == column-3)
			sprintf(sermsg.word,"%s",pres[i]);
		else if(i%column == column-2)            
			sprintf(sermsg.trans,"%s",pres[i]);   
		else if(i%column == column-1)            
		{
			sprintf(sermsg.time,"%s",pres[i]);  
			if(send(newfd,&sermsg,sizeof(sermsg),0)<0)    
			{                                             
				ERR_MSG("send");                          
				return -1;                                
			}
		}
	}
	if(i==(row+1)*column)
	{
		sermsg.type='S';   //查询完成标注
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)
		{
			ERR_MSG("send");
			return -1;
		}
	}
	if(i==0)
	{
		sermsg.type='F';   //查询完成标注
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)
		{
			ERR_MSG("send");
			return -1;
		}
	}
	//释放内存空间
	sqlite3_free_table(pres);
	return 0;
}
//查询单词回调函数,满足就会执行                                                                         
int find_callBack(void *arg, int column, char **column_text, char **column_name)  //void* arg = &flag  
{          

	strcat(sermsg.trans,column_text[1]);
	strcat(sermsg.trans,"\n");
	sermsg.type='S';                               
	fprintf(stderr,"查询单词成功\n"); 
	(*(int *)arg)++;
	return 0;                                                                                           
}                                                                                                       

int do_find(int newfd)    //查询单词函数
{

	//清空翻译
	bzero(sermsg.trans,sizeof(sermsg.trans));
	char sql[512];                                                         
	char *errmsg=NULL;
	int flag=0;
	sprintf(sql,"select * from wordbase where word=\"%s\";",sermsg.word);  
	if(sqlite3_exec(db,sql,find_callBack,&flag,&errmsg)!=SQLITE_OK)       
	{ 
		sermsg.type='E';
		fprintf(stderr,"newfd = %d 查询单词失败\n",newfd);
		//将数据包发送给客户端                   
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)    
		{                                           
			ERR_MSG("send");                        
			return -1;                              
		}                 	
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
		return-1;                                            
	}
	if(flag==2)
	{
		//将数据包发送给客户端                         
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)     
		{                                              
			ERR_MSG("send");                           
			return -1;                                 
		}
	}
	else{
		//将数据包发送给客户端
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)
		{
			ERR_MSG("send");
			return -1;
		}
	}
	//将查询信息插入到recordbase表格中
	//查询时间
	time_t t1;
	struct tm* timeinfo=NULL;
	time(&t1);
	timeinfo=localtime(&t1);
	char time1[256]="";
	sprintf(time1,"%d-%d-%d %d:%d:%d\n",timeinfo->tm_year+1900,timeinfo->tm_mon+1,timeinfo->tm_mday,\
			timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec);
	//插入历史记录表
	bzero(sql,sizeof(sql));                                             
	errmsg=NULL;                                           
	sprintf(sql,"insert into historybase values(\"%s\",\"%s\",\"%s\",\"%s\");",\
			sermsg.name,sermsg.word,sermsg.trans,time1);                        
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)        
	{                                                            

		return 0;
	}
	return 0;
}
int do_register(int newfd)   //注册函数
{
	char sql[364];
	char *errmsg=NULL;
	sprintf(sql,"insert into userbase values(\"%s\",\"%s\");",\
			sermsg.name,sermsg.password);
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		sermsg.type='E';
		fprintf(stderr,"newfd = %d 注册失败\n",newfd);
		//将数据包发送给客户端                   
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)    
		{                                           
			ERR_MSG("send");                        
			return -1;                              
		}                 	
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
		return-1;
	}
	sermsg.type='S';
	fprintf(stderr,"newfd = %d 注册成功\n",newfd);

	//将数据包发送给客户端                   
	if(send(newfd,&sermsg,sizeof(sermsg),0)<0)    
	{                                           
		ERR_MSG("send");                        
		return -1;                              
	}                                 
	return 1;
}
//登录查询回调函数,满足就会执行
int login_callBack(void *arg, int column, char **column_text, char **column_name)  //void* arg = &flag
{
	if(strcmp(column_text[0],sermsg.name)==0 && strcmp(column_text[1],sermsg.password)==0)
	{
		sermsg.type='S';                                
		*(int *)arg=1;
	}
	return 0;
}
int do_login(int newfd)   //登录函数
{
	char sql[512];
	char *errmsg=NULL;
	int flag=0;
	sprintf(sql,"select * from userbase where user=\"%s\";",sermsg.name);
	if(sqlite3_exec(db,sql,login_callBack,&flag,&errmsg)!=SQLITE_OK)                  
	{   
		fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);                 
		return -1;                              
	}
	if(flag==0)
	{
		sermsg.type='E';
		fprintf(stderr,"newfd = %d 登录失败\n",newfd);
		//将数据包发送给客 户端
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)
		{
			ERR_MSG("send");
			return -1;
		}
	}
	//说明注册信息表中有,可以登录,判断是否为登录状态
	else if(flag==1)
	{
		//将登陆信息保存到登录信息表中
		char sql[364];                                              
		char *errmsg=NULL;                                          
		sprintf(sql,"insert into recordbase values(\"%s\");",sermsg.name);                       
		if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)       
		{                                                           
			sermsg.type='R';
			fprintf(stderr,"登录重复\n");
			bzero(sermsg.name,sizeof(sermsg.name));
			//将数据包发送给客户端
			if(send(newfd,&sermsg,sizeof(sermsg),0)<0)
			{
				ERR_MSG("send");
				return -1;
			}
			fprintf(stderr,"line:%d sqlite3_exec:%s\n",__LINE__,errmsg);
			return 0;
		}
		fprintf(stdout,"%s 登录成功\n",sermsg.name);
		//设置为登录状态,登陆成功,将数据包发送给客户端                          
		if(send(newfd,&sermsg,sizeof(sermsg),0)<0)      
		{                                               
			ERR_MSG("send");                            
			return -1;                                  
		}    
	}
	return 0;
}

测试文件

#include "01_serfunc.h"
int main(int argc, const char *argv[])
{
	//捕获僵尸进程
	sighandler_t s = signal(SIGCHLD, handler);
    if(SIG_ERR == s)
    {
        perror("signal");
        return -1;
    }
	//创建套接字.链接客户端.绑定信息结构体
	int sfd=cli_net();
	//创建数据库导入单词
	sqlite3*db=sqlite3_database();
	//由于自动获取,只需要定义几个结构体变量进行接受,需要时直接访问里面成员即可
	struct sockaddr_in cin;
	socklen_t addrlen=sizeof(cin);
	//从已经完成链接的队列头获取一个客户端的信息,
	//生成一个新的文件描述符,新的才是用于和客户端通信的文件描述符
	pid_t pid=0;
	while(1)
	{
		//父进程负责处理客户连接
		int newfd=accept(sfd,(struct sockaddr *)&cin,&addrlen);
		if(newfd<0)                                                                           
		{
			ERR_MSG("accept");
			return -1;
		}
		printf("[%s:%d] newfd=%d 连接成功\n",\
				inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
		//创建子进程
		pid=fork();
		if(pid==0)
		{
		//	printf("进入接收函数\n");
			close(sfd);
			//接收消息
			ser_recv(newfd,cin);
			//退出子进程
			close(newfd);
			exit(0);
		}
		else if(pid>0)
		{
		//	close(newfd);
		}
		else
		{
			ERR_MSG("fork");
			return -1;
		}
	}
	//关闭数据库
	sqlite3_close(db);
	return 0;
}

客户端

头文件

#ifndef __FUNC_H__
#define __FUNC_H__
#include <stdio.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>

#define PORT 6666              
#define IP "192.168.100.17" 

#define ERR_MSG(msg) do{\
	fprintf(stderr,"line:__%d__\n",__LINE__);\
	perror(msg);\
}while(0)

struct msg{
	char type;             //消息类型
	char name[128];    //名字
	char password[128];   //密码
	char word[128];       //单词
	char trans[128];      //翻译
	char time[256];       //时间
}climsg;

void pri_menu(); //主菜单
void sec_menu();    //查询菜单
int cli_login(int sfd);   //登录
int cli_register(int sfd);    //注册
int cli_find(int sfd);       //查找单词
int cli_history(int sfd);     //查询历史记录	
int clisend(int sfd);   //发送函数
int clirecv(int sfd);  //接收函数
int cli_quit(int sfd);   //退出函数
int net_ser();     //创建套接字.链接客户端.绑定信息结构体
#endif

功能文件

#include "02_clifunc.h"
void pri_menu()    //主菜单
{
	printf("------欢迎来到电子词典-----\n");
	printf("--------1.注册-------------\n");
	printf("--------2.登录-------------\n");
	printf("--------3.退出-------------\n");
	printf("---------------------------\n");
}
void sec_menu()    //查询菜单
{
	printf("------欢迎来到电子词典-----\n");
	printf("--------4.查询单词---------\n");
	printf("--------5.历史查询记录-----\n");
	printf("--------6.退出-------------\n");
	printf("---------------------------\n");
}
int cli_quit(int sfd)   //退出
{
	//封装协议                                  
	climsg.type='6';                            
	//将数据包发送给服务器                      
	if(send(sfd,&climsg,sizeof(climsg),0)<0)    
	{                                           
		ERR_MSG("send");                        
		return -1;                              
	}              
	return 0;
}
int cli_history(int sfd)//查询历史记录
{
	//封装协议                                         
	climsg.type='5';                                         
	//将数据包发送给服务器                             
	if(send(sfd,&climsg,sizeof(climsg),0)<0)           
	{                                                  
		ERR_MSG("send");                               
		return -1;                                     
	}
	while(1)
	{	
		//阻塞接收服务器的回复                             
		if(recv(sfd,&climsg,sizeof(climsg),0)<0)           
		{                                                  
			ERR_MSG("recv");                               
			return -1;                                     
		} 
		if(climsg.type=='S')
			break;
		if(climsg.type=='F')
		{
			fprintf(stdout,"没有查询记录!");
			break;
		}
		fprintf(stdout,"%s %s %s %s\n",climsg.name,climsg.word,climsg.trans,climsg.time);
	}
	return 1;

}
int cli_find(int sfd)       //查找单词
{
	//封装协议                                            
	climsg.type='4';                                      
	printf("请输入要查询的单词>>>\n");                      
	fgets(climsg.word,sizeof(climsg.word),stdin);         
	climsg.word[strlen(climsg.word)-1]=0;                        
	//将数据包发送给服务器                                
	if(send(sfd,&climsg,sizeof(climsg),0)<0)              
	{                                                     
		ERR_MSG("send");                                  
		return -1;                                        
	}                                                     

	//阻塞接收服务器的回复                                
	if(recv(sfd,&climsg,sizeof(climsg),0)<0)              
	{                                                     
		ERR_MSG("recv");                                  
		return -1;                                        
	} 
	if(climsg.type=='S')
	{
		fprintf(stderr,"%s\n",climsg.trans);
	}
	else if(climsg.type=='E')
	{
		fprintf(stderr,"查询失败,请检查单词是否正确\n");
		return -1;
	}

	return 0;
}
int cli_login(int sfd)   //登录
{
	//封装协议
	climsg.type='2';
	printf("请输入登录用户名>>>\n");
	fgets(climsg.name,sizeof(climsg.name),stdin);   
	climsg.name[strlen(climsg.name)-1]=0;           
	printf("请输入登录密码>>>\n");
	fgets(climsg.password,sizeof(climsg.password),stdin);
	climsg.password[strlen(climsg.password)-1]=0;   

	//将数据包发送给服务器                    
	if(send(sfd,&climsg,sizeof(climsg),0)<0)  
	{                                         
		ERR_MSG("send");                      
		return -1;                            
	}                                         

	//阻塞接收服务器的回复                    
	if(recv(sfd,&climsg,sizeof(climsg),0)<0)  
	{                                         
		ERR_MSG("recv");                      
		return -1;                            
	}                                         
	if(climsg.type=='S')                       
	{                                          
		fprintf(stderr,"登录成功\n");
		return 1;
	}                                          
	else if(climsg.type=='E')                          
	{                                                  
		fprintf(stderr,"登录失败,请检查密码或者先注册\n");     
		return -1;
	}  
	else if(climsg.type=='R')                              
	{                                                      
   	 	fprintf(stderr,"重复登录\n"); 
		return -1;
	}                                                      
	return 1;                                          
}

int cli_register(int sfd)    //注册
{
	//封装协议
	climsg.type='1';
	bzero(climsg.name,sizeof(climsg.name));
	bzero(climsg.password,sizeof(climsg.password));
	printf("请输入注册的用户名>>>\n");

	fgets(climsg.name,sizeof(climsg.name),stdin);
	climsg.name[strlen(climsg.name)-1]=0;
	printf("请输入注册的密码>>>\n");
	fgets(climsg.password,sizeof(climsg.password),stdin);
	climsg.password[strlen(climsg.password)-1]=0;
    //将数据包发送给服务器
	if(send(sfd,&climsg,sizeof(climsg),0)<0)
	{
		ERR_MSG("send");
		return -1;
	}

	//阻塞接收服务器的回复
	if(recv(sfd,&climsg,sizeof(climsg),0)<0)
	{
		ERR_MSG("recv");
		return -1;
	}
	if(climsg.type=='S')
	{
		fprintf(stderr,"注册成功,请登录\n");
	}
	else if(climsg.type=='E')
	{
		fprintf(stderr,"注册失败,请更换用户名\n");
	}
	return 0;
}
//创建套接字.链接客户端.绑定信息结构体
int net_ser()
{
	//创建流式套接字
	int sfd = socket(AF_INET, SOCK_STREAM, 0);                                                     
	if(sfd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket success\n");
	//非必须绑定,连接服务器
	//填充地址信息结构体
	struct sockaddr_in sin; //定义结构体变量
	sin.sin_family=AF_INET;
	sin.sin_port=htons(PORT);
	sin.sin_addr.s_addr=inet_addr(IP);
	//绑定信息结构体
	if(connect(sfd,(struct sockaddr *)&sin,sizeof(sin))<0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");
	return sfd;

}

测试文件

#include "02_clifunc.h"

int main(int argc, const char *argv[])
{

	//创建套接字.链接服务器.绑定信息结构体
	int sfd=net_ser();
	char choose=0;
	char ct=0;
	while(1)
	{
START:  system("clear");
		pri_menu();  //主菜单界面   
		printf("请输入你的选项>>>\n");
		choose=getchar();
		while(getchar()!=10);
		switch(choose)
		{
		case '1':	
			//注册
			cli_register(sfd);
			break;
		case '2':
			//登录
			if(cli_login(sfd)>0)
			{
				while(1)
				{
				//进入查询菜单
				system("clear");
				sec_menu();
				printf("请输入你的选项>>>\n");
				ct=getchar();
				while(getchar()!=10);
				switch(ct)
				{
				case '4':
					//查询单词
					cli_find(sfd);
					break;
				case '5':
					//历史记录查询
					cli_history(sfd);
					break;
				case '6':
					//退出登录
					cli_quit(sfd);
					goto START;
				default:
					fprintf(stdout,"输入有误,请重新输入\n");
					break;
				}
				printf("输入任意字符清屏>>>\n");
				while(getchar()!=10);
				}
			case '3':
				//退出
				goto END;
				break;
			default:
				fprintf(stdout,"输入有误,请重新输入\n");
				break;
			}
		}
		printf("输入任意字符清屏>>>\n");
		while(getchar()!=10);

	}
END:
	close(sfd);  //关闭套接字   
	return 0;
}

实现效果

注册

 登录

查询单词

 查询历史记录

 退出第查询界面,清空登录状态

 退出第一层界面,客户端下线

 重复登录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/196607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS2022离线安装教程

官方教程下载和安装步骤 https://docs.microsoft.com/zh-cn/visualstudio/install/create-an-offline-installation-of-visual-studio?viewvs-2022 使用命令行创建本地布局 下载所需的 Visual Studio 版本的引导程序&#xff0c;并将其复制到要用作本地布局源位置的目录中。…

训练自己的GPT2模型(中文),踩坑与经验

GPT2与Bert、T5之类的模型很不一样&#xff01;&#xff01;&#xff01; 如果你对Bert、T5、BART的训练已经很熟悉&#xff0c;想要训练中文GPT模型&#xff0c;务必了解以下区别&#xff01;&#xff01;&#xff01; 官方文档里虽然已经有教程&#xff0c;但是都是英文&…

手撸低代码平台搭建(四)组件拖动自由布局的实现

前言 大家好,在前两篇文章中,我们走进了前端低代码的世界,并揭秘了低代码的核心——页面设计器的实现。在揭秘页面设计器时,我们重点分享了顺序排列布局的组件拖动方式,那篇文章的评论中,有小伙伴问到自由布局的实现,那么我们在这篇文章中来分享一下自由布局拖动的实现…

Echarts柱形头部圆弧处理

第008个点击查看专栏目录对于柱状图来说&#xff0c;我们想要的效果是圆柱的上面进行圆弧的处理&#xff0c;产生顺滑的感觉&#xff0c;怎么处理呢&#xff0c;只要设置好样式即可&#xff0c;参考源代码圆角半径&#xff0c;单位px&#xff0c;支持传入数组分别指定 4 个圆角…

VMware 多站点容灾之SRM部署实践

一、背景 在VMware 多云场景中&#xff0c;我们最初会通过vmware的副本机制手动克隆或主从模式完成一些节点的灾备&#xff0c;虽然在初期不会出现什么问题&#xff0c;但一旦出现灾备恢复的复杂度和数据丢失风险还是一大考验&#xff0c;基于此&#xff0c;我们可借助VMware v…

Qt 获取网络信息

在Qt Network模块中使用QHostAddress存放IP地址&#xff0c;QHostInfo类来获取主机名和IP。 进行TCP/UDP编程时&#xff0c;需要将连接的主机名解析为IP地址&#xff0c;这个操作用DNS协议执行。 在互联网中现在有两种IP类型&#xff1a;IVP4和IVP6。 IP地址是给每一个连接在互…

Linux操作系统之基础IO

目录 系统IO调用接口 open write read 理解文件描述符fd 理解Linux操作系统的设计哲学&#xff0c;多态的思想是如何应用在Linux文件系统的 输出&#xff0c;追加&#xff0c;输入重定向的本质 子进程共享父进程的文件 IO的两个缓冲区 Linux特有的EXT文件系统 磁盘系…

代码训练营第二十天|530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先

530 .二叉搜索树的最小绝对差 看完题后的思路 因为是二叉搜索树&#xff0c;所以直接按照二叉搜索树中序遍历&#xff0c;得到递增序列。遍历过程中一个指针指向遍历过的前一个元素 prenull&#xff1b; void f&#xff08;root&#xff09;if rootnull return递归 f&#x…

git语义化定制版本规范

目录说明说明 语义化版本控制规范,语义化的版本控制规范要求版本号由三部分构成&#xff1a;x.y.z MAJOR&#xff08;X&#xff09;&#xff1a;这个是主版本号&#xff0c;一般是涉及到不兼容的 API 更改时&#xff0c;这个会变化。MINOR&#xff08;Y&#xff09;&#xff…

剑指Offer pow() 函数实现(快速幂)!!!

剑指 Offer 16. 数值的整数次方 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff09;。不得使用库函数&#xff0c;同时不需要考虑大数问题。 示例 1&#xff1a; 输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000 示…

早已有所耳闻的堆排序,你知道如何用C语言实现吗? 【堆排序|C语言版】

目录 0.写在前面 1.什么是堆&#xff1f; 2. 堆排序 2.1 建堆 2.1.1 AdjustUp&#xff08;向上调整算法&#xff09; 2.1.2 AdjustDown&#xff08;向下调整算法&#xff09; 2.2 两种建堆算法的时间复杂度 2.2.1 AdjustUp建堆的时间复杂度 2.2.2 AdjustDown建堆的时间…

神经网络(模型)量化介绍 - PTQ 和 QAT

神经网络&#xff08;模型&#xff09;量化介绍 - PTQ 和 QAT1. 需求目的2. 量化简介3. 三种量化模式3.1 Dynamic Quantization - 动态量化3.2 Post-Training Static Quantization - 训练后静态量化3.3 Quantization Aware Training - 量化感知训练4. PTQ 和 QAT 简介5. 设备和…

Flutter 小技巧之 3.7 性能优化background isolate

Flutter 3.7 的 background isolate 绝对是一大惊喜&#xff0c;尽管它在 release note 里被一笔带过 &#xff0c;但是某种程度上它可以说是 3.7 里最实用的存在&#xff1a;因为使用简单&#xff0c;提升又直观。 Background isolate YYDS 前言 我们知道 Dart 里可以通过新建…

CODESYS开发教程9-文件读写(CAA File库)

今天继续我们的小白教程&#xff0c;老鸟就不要在这浪费时间了&#x1f60a;。 前面一期我们介绍了CODESYS的定时器及触发相关的功能块。这一期主要介绍CODESYS的CAA.File库中的目录和文件读写功能块&#xff0c;主要包括文件路径、名称、大小的获取以及文件的创建、打开、读、…

软测(概念) · 软件测试的基本概念 · 什么是需求 · 测试用例的概念 · 软件错误(bug)的概念

一、什么是软件测试软件测试和开发的区别测试和调试的区别一个优秀的软件测试人员具备的素质二、什么是需求从测试人员角度看待需求三、测试用例的概念四、软件错误&#xff08;bug&#xff09;的概念一、什么是软件测试 最常见的解释是&#xff1a;软件测试就是找 BUG&#x…

个人博客美化

总体参考&#xff1a; Butterfly 文档&#xff1a;https://butterfly.js.organzhiyu &#xff1a;https://anzhiy.cn张洪 Heo &#xff1a;https://blog.zhheo.comLeonus &#xff1a;https://blog.leonus.cn 注&#xff1a;博客所有美化大部分&#xff08;全部&#xff09;都参…

React项目实战之租房app项目(九)登录模块基础布局和功能实现

前言 目录前言一、房屋详情模块二、登录模块2.1 登录模块效果图2.2 基础布局2.3 调用接口实现登录2.4 实现表单验证功能2.4.1 formik介绍2.4.2 formik基本使用2.4.3 添加表单验证2.5 代码优化总结一、房屋详情模块 房屋详情模块主要是展示之前获取到的房源信息&#xff0c;由于…

为防护加码,飞凌嵌入式i.MX93系列开发板让通信安全又稳定

来源&#xff1a;飞凌嵌入式官网www.forlinx.com随着新基建的加快推进&#xff0c;智能制造迎来了更好的发展时机&#xff0c;嵌入式板卡等智能设备也在更多的应用场景中大放异彩。但随着现场的设备数量的剧增&#xff0c;环境中的各种干扰信号也随之增加&#xff0c;这就对设备…

windows下GitHub的SSH key配置

SSH Key 是一种方法来确定受信任的计算机&#xff0c;从而实现免密码登录。 Git是分布式的代码管理工具&#xff0c;远程的代码管理是基于SSH的&#xff0c;所以要使用远程的Git则需要SSH的配置。 下面的步骤将完成 生成SSH密钥 并 添加公共密钥到GitHub上的帐户 先设置GitHub…

Apifox接口测试工具详细解析

最近发现一款接口测试工具--apifox&#xff0c;我我们很难将它描述为一款接口管理工具 或 接口自测试工具。 官方给了一个简单的公式&#xff0c;更能说明apifox可以做什么。 Apifox Postman Swagger Mock JMeter Apifox的特点&#xff1a; 接口文档定义&#xff1a; Apif…