项目需求
- 登录注册功能
- 单词查询功能
- 历史记录功能
- 支持多客户端连接
- 采用数据库保存用户信息与历史记录
- 将dict.txt的数据导入到数据库中保存
开发步骤
1.流程图(一个大致的思路和想法)
2.根据流程图写框架(像做填空题一样,先写出题目,后去填充)
3.逐步实现每个功能(会发现流程图中的错误,回过头去补充完善)
服务器
#include <stdio.h>
#include <string.h>
#include <sqlite3.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
//3个table名
#define USR "usr"
#define DICT "dict"
#define RECORD "record"
//size定义
#define SQLLEN 100
#define SIZE 150 //词典一行字符串读取长度限制
#define EN 50 //英文字符串长度限制
#define CN 100 //中文字符串长度限制
#define TYPLEN 20
#define USRLEM 20
#define PWDLEN 20
#define HISLEM 80
#define DATLEN 30
#define ERR_LOG(errmsg) do{\
perror(errmsg);\
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
typedef struct protocol{
char type[TYPLEN];
char usrname[USRLEM];
char passwd[PWDLEN];
char en[EN];
char zh_CN[CN];
char history[HISLEM];
}DATAFRAME;
//函数定义
int create_table(sqlite3* db,char* sql);//创建一个表
int get_all_table(sqlite3* db,char* table_name,int isprintf);//查询表中全部数据,可选择是否打印
int insert_alldict(sqlite3* db);//导入词典到数据库中的dict表
//select name from table_name where name="usrname";
int select_usr_intable(sqlite3* db,char* value,int isprintf);
//select en from dict where en="xxxxx";
int select_en_intable(sqlite3* db,char* value,int isprintf);
//select en from dict where en="xxxxx";
char* select_zh_intable(sqlite3* db,char* value,int isprintf);
//select column1, column2 from table_name where column1="value1" and column2="value2";
int select_pwd_sta_intable(sqlite3* db,char* table_name,char* column1,char* column2,char* value1,char* value2,int isprintf);
//select time, record ,name from history where name="xxxxx";
int select_history_intable(sqlite3* db,char* value,int isprintf);
void get_history(sqlite3* db,char* value);
int insert_usr(sqlite3* db,char* value1,char* value2,char* value3);//增加用户数据到表
int insert_history(sqlite3* db,char* value1,char* value2,char* value3);//增加查词记录数据到表history
int update_usrstate(sqlite3* db,char* name,char* state);//修改用户状态
int update_allusrstate(sqlite3* db);//启动,初始化全部用户状态state="0"
int update_maxfd(int maxfd,fd_set readfds);//更新maxfd
char* get_time(char* date);//获取当前日期和时间
//全局变量
char** all_result;//全部历史记录
char** send_result;//全部历史记录
int send_k=0;
int send_row=0;//行
int send_column=0;//列
int main(int argc, char const *argv[])
{
if(argc < 3)
{
printf("请输入本地IP号和端口号\n");
return 0;
}
//创建(打开)一个数据库
sqlite3* db = NULL;
char* errmsg = NULL;
if(sqlite3_open("./dictionary.db",&db) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
printf("数据库打开(创建)成功\n");
//创建(打开)3个表
char sql[SQLLEN] = "create table if not exists usr(name char primary key,passwd char,state char);";
if(create_table(db,sql) < 0)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表usr失败");
}
printf("表usr打开(创建)成功\n");
bzero(sql,SQLLEN);
strcpy(sql,"create table if not exists dict(en char,zh_CN char);");
if(create_table(db,sql) < 0)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表dict失败");
}
printf("表dict打开(创建)成功\n");
bzero(sql,SQLLEN);
strcpy(sql,"create table if not exists history(time char,record char,name char);");
if(create_table(db,sql) < 0)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,"打开(创建)表history失败");
}
printf("表history打开(创建)成功\n");
//启动,初始化全部用户状态state="0"
update_allusrstate(db);
//如果表dict为空,重新导入原始词典数据
int dict_row = get_all_table(db,DICT,0);
printf("表dict单词数:%d\n",dict_row);
if(dict_row == 0)
{
insert_alldict(db);
printf("词典导入数据库成功\n");
printf("表dict单词数:%d\n",get_all_table(db,DICT,0));
}
//socket套接字
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd < 0)
{
ERR_LOG("socket");
return -1;
}
//端口快速重用
int reuse = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(int)) < 0)
{
ERR_LOG("setsockopt");
return -1;
}
//bind
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(*(unsigned short*)argv[2]);
saddr.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
{
ERR_LOG("bind");
return -1;
}
//listen
if(listen(sfd,5) < 0)
{
ERR_LOG("listen");
return -1;
}
//变量定义
DATAFRAME buf = {{0},{0},{0},{0},{0},{0}};
struct sockaddr_in caddr;
socklen_t caddrlen = sizeof(caddr);
fd_set readfds,tempfds;
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
FD_SET(sfd,&readfds);
int maxfd = 0;
maxfd = sfd;
int cfd,recv_len,i;
char date[DATLEN] = "";
printf("服务器启动成功,等待客户端连接\n");
while(1)
{
tempfds = readfds;
int selret = select(maxfd+1,&tempfds,NULL,NULL,NULL);
if(selret <= 0)
{
ERR_LOG("select");
return -1;
}
for(i=0;i<=maxfd;i++)
{
if(!FD_ISSET(i,&tempfds))
{
continue;
}
if(i == sfd)//accept连接事件
{
cfd = accept(sfd,(struct sockaddr*)&caddr,&caddrlen);
if(cfd < 0)
{
ERR_LOG("accept");
return -1;
}
printf("有新客户端连接成功\n");
FD_SET(cfd,&readfds);
maxfd = maxfd>cfd ? maxfd : cfd;
}
else if(i > 3)//客户端交互事件
{
bzero(buf.type,TYPLEN);
recv_len = recv(i,&buf,sizeof(DATAFRAME),0);
if(recv_len < 0)
{
ERR_LOG("recv");
return -1;
}
else if(0 == recv_len)
{
//printf("fd = %d的客户端断开连接\n",i);//test
close(i);
FD_CLR(i,&readfds);
//更新maxfd
maxfd = update_maxfd(maxfd,readfds);
}
else
{
printf("%s 收到来自[%s:%d]客户端的请求信息:%s\n",get_time(date),inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),buf.type);
//注册请求
if(memcmp("register",buf.type,sizeof("register")) == 0)
{
//查询用户是否注册
// select name from usr where name="xxxxx";
if(select_usr_intable(db,buf.usrname,1) == 0)//未注册
{
//增加用户
if(insert_usr(db,buf.usrname,buf.passwd,"0") == 0)
{
printf("%s 新增用户%s到表usr成功\n",get_time(date),buf.usrname);
}
else
printf("新增用户失败\n");
bzero(buf.type,TYPLEN);
strcpy(buf.type,"success");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//已注册
{
bzero(buf.type,TYPLEN);
strcpy(buf.type,"repeat");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
}
//登录请求
else if(memcmp("login",buf.type,sizeof("login")) == 0)
{
//查询用户是否存在
// select name from usr where name="xxxxx";
if(select_usr_intable(db,buf.usrname,1) == 0)//不存在
{
bzero(buf.type,TYPLEN);
strcpy(buf.type,"nulluser");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//用户已存在
{
//查询密码是否正确
//select name, passwd from usr where name="xxxx" and passwd="xxxxx";
if(select_pwd_sta_intable(db,USR,"name","passwd",buf.usrname,buf.passwd,1) == 0)//密码不正确
{
printf("%s 用户%s尝试登录,密码错误\n",get_time(date),buf.usrname);
bzero(buf.type,TYPLEN);
strcpy(buf.type,"passwderr");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//密码正确
{
//查询用户是否已登录
//select name, state from usr where name="xxxx" and state="xxxxx";
if(select_pwd_sta_intable(db,USR,"name","state",buf.usrname,"0",1) == 0)//用户已登录
{
printf("%s 用户%s重复登录请求,已拒绝\n",get_time(date),buf.usrname);
bzero(buf.type,TYPLEN);
strcpy(buf.type,"relogin");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//用户未登录,允许登录
{
//修改用户状态state="1"
update_usrstate(db,buf.usrname,"1");
printf("%s 用户%s上线了\n",get_time(date),buf.usrname);
bzero(buf.type,TYPLEN);
strcpy(buf.type,"allowlogin");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
}
}
}
//查单词请求
else if(memcmp("en",buf.type,sizeof("en")) == 0)
{
//插入历史记录
char hdate[DATLEN] = "";
strcpy(hdate,get_time(date));
if(insert_history(db,hdate,buf.en,buf.usrname) == 0)
{
printf("%s 新增查词记录%s %s到表history成功\n",get_time(date),date,buf.en);
}
else
printf("新增历史记录失败\n");
//查询英文是否存在
//select en from dict where en="xxxxx";
if(select_en_intable(db,buf.en,1) == 0)//不存在
{
bzero(buf.type,TYPLEN);
strcpy(buf.type,"noen");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//存在
{
bzero(buf.zh_CN,CN);
//获取中文
strcpy(buf.zh_CN,select_zh_intable(db,buf.en,0));
bzero(buf.type,TYPLEN);
strcpy(buf.type,"zh");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
}
//查历史记录请求
else if(memcmp("history",buf.type,sizeof("history")) == 0)
{
//查找属于用户的历史记录
if(select_history_intable(db,buf.usrname,1) == 0)//没有历史记录
{
bzero(buf.type,TYPLEN);
strcpy(buf.type,"nohistory");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else//有历史查询记录
{
send_k = 0;
get_history(db,buf.usrname);
send_result = all_result+3;
int m=0,n=0;
for(m=0;m<send_row;m++)
{
bzero(buf.history,HISLEM);
for(n=0;n<send_column;n++)
{
if(n == send_column-1)
{
break;
}
else if(n == 0)
{
strcpy(buf.history,send_result[send_k]);
//printf("n=%d,%s",n,send_result[send_k]);//test
}
else if(n == 1)
{
strcat(buf.history," ");
strcat(buf.history,send_result[send_k]);
//printf("n=%d,%s",n,send_result[send_k]);//test
}
send_k++;
}
putchar(10);
send_k++;
bzero(buf.type,TYPLEN);
strcpy(buf.type,"continue");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
bzero(buf.type,TYPLEN);
strcpy(buf.type,"finish");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
}
//退出登录请求
else if(memcmp("logout",buf.type,sizeof("logout")) == 0)
{
//修改用户状态state="0"
update_usrstate(db,buf.usrname,"0");
printf("%s 用户%s下线了\n",get_time(date),buf.usrname);
bzero(buf.type,TYPLEN);
strcpy(buf.type,"allowlogout");
if(send(i,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
}
else if(memcmp("signallogout",buf.type,sizeof("signallogout")) == 0)
{
//中断退出,修改用户状态state="0"
update_usrstate(db,buf.usrname,"0");
printf("%s 用户%s下线了\n",get_time(date),buf.usrname);
}
}
}
}
}
close(sfd);
//关闭数据库
sqlite3_close(db);
printf("数据库已关闭\n");
return 0;
}
//创建一个表
int create_table(sqlite3* db,char* sql)
{
char* errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
return 0;
}
//查询表中全部数据,可选择是否打印
int get_all_table(sqlite3* db,char* table_name,int isprintf)
{
char sql[SQLLEN] = "";
sprintf(sql,"select * from %s;",table_name);
char** result = NULL;
int row = 0,column = 0;
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
int i=0,j=0,k=0;
if(isprintf)
{
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-10s\t",result[k]);
k++;
}
putchar(10);
}
}
return row;
}
//导入词典到数据库中的dict表
int insert_alldict(sqlite3* db)
{
char sql[SQLLEN] = "";
//打开词典
FILE *fp = fopen("./dict.txt","r");
if(fp == NULL)
{
ERR_LOG("fopen");
return -1;
}
char word[SIZE] = "";
while(fgets(word,SIZE,fp) != NULL)
{
//拆分中英文
char en[EN]="",zh_CN[CN]="";
int en_len=0,ch_len=0;
char *p=word;
while(*p!=' ')
{
p++;
en_len++;
}
strncpy(en,word,en_len);//得到英文
while(*p==' ')p++;
char *c=p;
while(*p!='\0')
{
p++;
ch_len++;
}
strncpy(zh_CN,c,ch_len);//得到释义中文
bzero(sql,SQLLEN);
sprintf(sql,"insert into dict values(\"%s\",\"%s\");",en,zh_CN);
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s en_word:%s\n",__LINE__,__func__,errmsg,en);
return -1;
}
}
fclose(fp);
return 0;
}
//存在返回1,不存在返回0
//isprintf==1,打印查询的结果
//select name from usr where name="usrname";
int select_usr_intable(sqlite3* db,char* value,int isprintf)
{
char sql[SQLLEN] = "";
//select name from usr where name="sheng";
sprintf(sql,"select name from usr where name=\"%s\";",value);
char** result;
int row,column;
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
int i=0,j=0,k=0;
if(isprintf)
{
printf("_____________________________\n");
printf("select_usr_intable:\n");
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-10s\t",result[k]);
k++;
}
putchar(10);
}
printf("_____________________________\n");
}
return row;
}
//select en from dict where en="xxxxx";
int select_en_intable(sqlite3* db,char* value,int isprintf)
{
char sql[SQLLEN] = "";
//select en from dict where en="xxxxx";
sprintf(sql,"select en from dict where en=\"%s\";",value);
char** result;
int row,column;
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
int i=0,j=0,k=0;
if(isprintf)
{
printf("_____________________________\n");
printf("select_en_intable:\n");
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-10s\t",result[k]);
k++;
}
putchar(10);
}
printf("_____________________________\n");
}
return row;
}
//获取中文
//select en from dict where en="xxxxx";
char* select_zh_intable(sqlite3* db,char* value,int isprintf)
{
char sql[SQLLEN] = "";
//select en, zh_CN from dict where en="xxxxx";
sprintf(sql,"select en, zh_CN from dict where en=\"%s\";",value);
char** result;
int row,column;
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return NULL;
}
int i=0,j=0,k=0;
if(isprintf)
{
printf("_____________________________\n");
printf("select_zh_intable:\n");
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-10s\t",result[k]);
k++;
}
putchar(10);
}
printf("_____________________________\n");
}
return result[3];
}
//select time, record ,name from history where name="xxxxx";
int select_history_intable(sqlite3* db,char* value,int isprintf)
{
char sql[SQLLEN] = "";
//select time, record ,name from history where name="xxxxx";
int row,column;
char** result;
sprintf(sql,"select time, record ,name from history where name=\"%s\";",value);
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
int i=0,j=0,k=0;
if(isprintf)
{
printf("_____________________________\n");
printf("select_history_intable:\n");
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-20s\t",result[k]);
k++;
}
putchar(10);
}
printf("_____________________________\n");
}
return row;
}
//select time, record ,name from history where name="xxxxx";
void get_history(sqlite3* db,char* value)
{
char sql[SQLLEN] = "";
//select time, name from history where name="xxxxx";
sprintf(sql,"select time, record ,name from history where name=\"%s\";",value);
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&all_result,&send_row,&send_column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return;
}
}
//select column1, column2 from table_name where column1="value1" and column2="value2";
int select_pwd_sta_intable(sqlite3* db,char* table_name,char* column1,char* column2,char* value1,char* value2,int isprintf)
{
char sql[SQLLEN] = "";
sprintf(sql,"select %s, %s from %s where %s=\"%s\" and %s=\"%s\";",column1,column2,table_name,column1,value1,column2,value2);
char** result;
int row,column;
char* errmsg = NULL;
if(sqlite3_get_table(db,sql,&result,&row,&column,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
int i=0,j=0,k=0;
if(isprintf)
{
printf("_____________________________\n");
printf("select_pwd_sta_intable:\n");
for(i=0;i<=row;i++)//行 = 字符段1行 + 记录段row行
{
for(j=0;j<column;j++)//列
{
printf("%-10s\t",result[k]);
k++;
}
putchar(10);
}
printf("_____________________________\n");
}
return row;
}
//修改用户状态
int update_usrstate(sqlite3* db,char* name,char* state)
{
char sql[SQLLEN] = "";
sprintf(sql,"update usr set state=\"%s\" where name=\"%s\";",state,name);
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
return 0;
}
//启动,初始化全部用户状态state="0"
int update_allusrstate(sqlite3* db)
{
char sql[SQLLEN] = "";
sprintf(sql,"update usr set state=\"0\";");
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
return 0;
}
//增加用户数据到表usr
int insert_usr(sqlite3* db,char* value1,char* value2,char* value3)
{
char sql[SQLLEN] = "";
sprintf(sql,"insert into usr values(\"%s\",\"%s\",\"%s\");",value1,value2,value3);
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
return 0;
}
//增加查词记录数据到表history
int insert_history(sqlite3* db,char* value1,char* value2,char* value3)
{
char sql[SQLLEN] = "";
sprintf(sql,"insert into history values(\"%s\",\"%s\",\"%s\");",value1,value2,value3);
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
{
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,errmsg);
return -1;
}
return 0;
}
//更新maxfd
int update_maxfd(int maxfd,fd_set readfds)
{
int i;
for(i=maxfd;i>=0;i--)
{
if(FD_ISSET(i,&readfds))
{
return i;
}
}
return 0;
}
//获取当前日期和时间
char* get_time(char* date)
{
time_t t;
time(&t);
struct tm *tm = localtime(&t);
strftime(date,DATLEN,"[%Y-%m-%d %H:%M:%S]",tm);
return date;
}
客户端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
//size定义
#define EN 50
#define CN 100
#define TYPLEN 20
#define USRLEM 20
#define PWDLEN 20
#define HISLEM 80
#define ERR_LOG(errmsg) do{\
perror(errmsg);\
fprintf(stderr,"%d %s %s\n",__LINE__,__func__,__FILE__);\
}while(0)
typedef struct protocol{
char type[TYPLEN];
char usrname[USRLEM];
char passwd[PWDLEN];
char en[EN];
char zh_CN[CN];
char history[HISLEM];
}DATAFRAME;
typedef struct arg{
int sfd;
DATAFRAME buf;
}ARG;
//全局变量
int sfd;
DATAFRAME buf = {{0},{0},{0},{0},{0},{0}};
int flag_inquiry,flag_logout;
//ctrl+c结束进程
typedef void (*sighandler_t)(int);
void handler_quit(int sig)
{
bzero(buf.type,TYPLEN);
strcpy(buf.type,"signallogout");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return;
}
putchar(10);
close(sfd);
exit(0);
}
//接收线程
void* handler_recv(void *arg)
{
int* sfd = &((*(ARG*)arg).sfd);
DATAFRAME* buf = &((*(ARG*)arg).buf);
pthread_detach(pthread_self());
int recv_len;
while(1)
{
bzero(buf->type,TYPLEN);
recv_len = recv(*sfd,buf,sizeof(DATAFRAME),0);
if(recv_len < 0)
{
ERR_LOG("recv");
return NULL;
}
else if(0 == recv_len)
{
printf("服务器关闭,退出\n");
close(*sfd);
exit(1);
}
else
{
if(memcmp("success",buf->type,sizeof("success")) == 0)
{
printf("**注册成功(按回车继续)\n");
}
else if(memcmp("repeat",buf->type,sizeof("repeat")) == 0)
{
printf("**该用户名已注册,请换个用户名重新注册(按回车继续)\n");
}
else if(memcmp("nulluser",buf->type,sizeof("nulluser")) == 0)
{
printf("**用户不存在,请注册用户后登录(按回车继续)\n");
}
else if(memcmp("passwderr",buf->type,sizeof("passwderr")) == 0)
{
printf("**密码错误,请重新登录(按回车继续)\n");
}
else if(memcmp("relogin",buf->type,sizeof("relogin")) == 0)
{
printf("**该用户已登录,请勿重复登录(按回车继续)\n");
}
else if(memcmp("allowlogin",buf->type,sizeof("allowlogin")) == 0)
{
flag_inquiry = 1;
printf("**登录成功(按回车继续)\n");
}
else if(memcmp("noen",buf->type,sizeof("noen")) == 0)
{
printf(">>抱歉,词典中没有这个英文单词,请重新输入(按回车继续)\n");
}
else if(memcmp("zh",buf->type,sizeof("zh")) == 0)
{
//输出中文
printf(">>%s\n",buf->zh_CN);
printf("(按回车继续)\n");
}
else if(memcmp("nohistory",buf->type,sizeof("nohistory")) == 0)
{
printf(">>没有查词历史记录,请查词(按回车继续)\n");
}
else if(memcmp("continue",buf->type,sizeof("continue")) == 0)
{
printf(">>%s\n",buf->history);
}
else if(memcmp("finish",buf->type,sizeof("finish")) == 0)
{
printf(">>查词历史记录打印完毕(按回车继续)\n");
}
else if(memcmp("allowlogout",buf->type,sizeof("allowlogout")) == 0)
{
flag_logout = 1;
printf("(按回车继续)\n");
}
}
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
if(argc < 3)
{
printf("请输入服务器IP号和端口号\n");
return 0;
}
//注册SIGINT信号
sighandler_t s;
s = signal(SIGINT, handler_quit);
if(s == SIG_ERR)
{
ERR_LOG("signal");
return -1;
}
//创建socket套接字
sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd < 0)
{
ERR_LOG("socket");
return -1;
}
//connect连接服务端
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(*(unsigned short*)argv[2]);
saddr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(sfd,(struct sockaddr*)&saddr,sizeof(saddr)) < 0)
{
ERR_LOG("connect");
return -1;
}
//printf("连接成功\n");//test
//变量定义
ARG arg = {sfd,buf};
char option;
flag_inquiry = 0;
flag_logout = 0;
//创建发送数据线程
pthread_t tid;
if(pthread_create(&tid,NULL,handler_recv,(void*)&arg) != 0)
{
ERR_LOG("pthread_creat");
return -1;
}
//发送数据主线程
while(1)
{
//用户登录界面
system("clear");
printf("****************************\n");
printf("**1.注册 2.登录 3.退出**\n");
printf("****************************\n");
printf("**请输入选项-->");
scanf("%c",&option);
getchar();
switch(option)
{
case '1'://注册
bzero(buf.usrname,USRLEM);
printf("**请输入注册名-->");
fgets(buf.usrname,USRLEM,stdin);
buf.usrname[strlen(buf.usrname)-1] = 0;
bzero(buf.passwd,PWDLEN);
printf("**输入注册密码-->");
fgets(buf.passwd,PWDLEN,stdin);
buf.passwd[strlen(buf.passwd)-1] = 0;
bzero(buf.type,TYPLEN);
strcpy(buf.type,"register");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
while(getchar()!=10);
break;
case '2'://登录
bzero(buf.usrname,USRLEM);
printf("**请输入登录名-->");
fgets(buf.usrname,USRLEM,stdin);
buf.usrname[strlen(buf.usrname)-1] = 0;
bzero(buf.passwd,PWDLEN);
printf("**输入登录密码-->");
fgets(buf.passwd,PWDLEN,stdin);
buf.passwd[strlen(buf.passwd)-1] = 0;
bzero(buf.type,TYPLEN);
strcpy(buf.type,"login");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
while(getchar()!=10);
if(flag_inquiry)
{
goto INQUIRY;
}
break;
case '3'://退出
goto QUIT;
break;
default:
printf("**输入选项错误,请输入提供的选项(按回车继续)");
while(getchar()!=10);
break;
}
}
INQUIRY:
while(1)
{
//用户查询界面
system("clear");
printf(">>>>>>>>>>>>>><<<<<<<<<<<<<<\n");
printf(">>1.查词 2.历史 3.退出<<\n");
printf(">>>>>>>>>>>>>><<<<<<<<<<<<<<\n");
printf(">>请输入选项-->");
scanf("%c",&option);
getchar();
switch(option)
{
case '1'://查单词
bzero(buf.en,EN);
printf(">>请输入要查询的英文单词-->");
fgets(buf.en,EN,stdin);
buf.en[strlen(buf.en)-1] = 0;
bzero(buf.type,TYPLEN);
strcpy(buf.type,"en");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
while(getchar()!=10);
break;
case '2'://查历史记录
bzero(buf.type,TYPLEN);
strcpy(buf.type,"history");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
while(getchar()!=10);
break;
case '3'://退出登录
bzero(buf.type,TYPLEN);
strcpy(buf.type,"logout");
if(send(sfd,&buf,sizeof(DATAFRAME),0) < 0)
{
ERR_LOG("send");
return -1;
}
while(getchar()!=10);
if(flag_logout)
{
goto QUIT;
}
break;
default:
printf(">>输入选项错误,请输入提供的选项(按回车继续)");
while(getchar()!=10);
break;
}
}
QUIT:
printf("**退出成功\n");
close(sfd);
return 0;
}
演示
本文链接:https://shengto.top/network_programming/tcp_dictionary.html
转载时须注明出处及本声明