服务器端:
Ser.h
#ifndef __SER_H__
#define __SER_H__
#include <myhead.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__:",__LINE__);\
perror(msg);\
}while(0)
//用于客户端与服务器传递消息的结构体
typedef struct {
char type; //协议
char username[20];
char password[20];
char text[128];
}MSG;
#define PORT 8888 //端口号
#define IP "127.0.0.1" //本地主机地址
//响应信号函数
void handler(int sig);
//将dict.txt导入到数据库中
int dicttosql();
//接收信息函数
int do_recv(int newfd);
//注册函数
int do_register(int newfd,sqlite3* db,MSG msg);
//登录函数
int do_login(int newfd,sqlite3* db,MSG msg);
//查询函数
int do_select(int newfd,sqlite3* db,MSG msg);
//历史记录函数
int do_history(int newfd,sqlite3* db,MSG msg);
//退出登录函数
int do_exit(sqlite3* db,MSG msg);
#endif
Ser.c
#include "Ser.h"
//响应信号函数
void handler(int sig){
while(waitpid(-1,NULL,WNOHANG)>0);
}
//将dict.txt导入到数据库中
int dicttosql()
{
//以只读的方式打开dict.txt文件
FILE* fd;
if((fd=fopen("./dict.txt","r")) == NULL){
ERR_MSG("open");
return -1;
}
//打开数据库
sqlite3* db=NULL;
if(sqlite3_open("./my.db", &db) != 0){
fprintf(stderr,"__%d__sqlite3_open: %s",\
__LINE__, sqlite3_errmsg(db));
return -1;
}
//创建数据表dict
char sql[128]="";
sprintf(sql, "create table if not exists dict(word char,mean char);");
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != 0){
fprintf(stderr, "__%d__create:%s\n",\
__LINE__,errmsg);
return -1;
}
//创建数据表user
sprintf(sql, "create table if not exists user(username char primary key,password char,flag char);");
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) != 0){
fprintf(stderr, "__%d__create:%s\n",\
__LINE__,errmsg);
return -1;
}
char buf[128]="";
char word[64]="";
char mean[64]="";
while(fgets(buf,128,fd) != NULL){
buf[strlen(buf)-1]=0;
for(int i=0;i<strlen(buf);i++){
if(buf[i]!=' ' && buf[i+1]==' ' && buf[i+2]==' '){
strncpy(word,buf,i+1);
}
if(buf[i]==' ' && buf[i+1]==' ' && buf[i+2]!=' '){
strcpy(mean,buf+i+2);
}
}
//将word,mean插入到数据库中
char sql[128]="";
sprintf(sql,"insert into dict values(\"%s\",\"%s\");", word, mean);
char *errmsg = NULL;
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg) !=0){
fprintf(stderr, "__%d__insert:%s\n",\
__LINE__,errmsg);
return -1;
}
//清空buf,word,mean
bzero(buf,128);
bzero(word,64);
bzero(mean,64);
}
printf("导入成功\n");
//关闭文件
fclose(fd);
//关闭数据库
sqlite3_close(db);
return 0;
}
int do_recv(int newfd){
MSG msg;
//打开数据库
sqlite3* db=NULL;
if(sqlite3_open("./my.db", &db) != 0){
fprintf(stderr,"__%d__sqlite3_open: %s",__LINE__, sqlite3_errmsg(db));
return -1;
}
int flag=0;
while(1){
if(-1 == recv(newfd,&msg,sizeof(msg),0)){
ERR_MSG("recv");
return -1;
}
switch(msg.type){
case 'R':
//注册函数
do_register(newfd,db,msg);
break;
case 'L':
//登录函数
do_login(newfd,db,msg);
break;
case 'S':
//查询函数
do_select(newfd,db,msg);
break;
case 'H':
//历史记录函数
do_history(newfd,db,msg);
break;
case 'E':
//退出登录函数
do_exit(db,msg);
break;
case 'Q':
flag=1;
}
if(flag==1){
break;
}
}
//关闭数据库
sqlite3_close(db);
return 0;
}
int do_register(int newfd,sqlite3* db,MSG msg){
char sql[128]="";
sprintf(sql,"insert into user values(\"%s\",\"%s\",\"%c\");",msg.username,msg.password,'N');
//将用户信息添加到表中
char* errmsg = NULL;
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
//判断用户是否已经在表中了
if(sqlite3_errcode(db) == 19)
{
printf("用户名[%s]请勿重复注册\n",msg.username);
//重复注册
msg.type='F';
strcpy(msg.text,"用户名重复");
//发送给客户端
if(send(newfd,&msg,sizeof(msg),0) < 0)
{
ERR_MSG("send");
return -1;
}
return -1;
}
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
}
msg.type='T';
//创建一张历史记录表
sprintf(sql,"create table if not exists %s (word char,mean char,time char);",msg.username);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
printf("用户名[%s]注册成功\n",msg.username);
strcpy(msg.text,"注册成功");
//发送给客户端
if(send(newfd,&msg,sizeof(msg),0) < 0)
{
ERR_MSG("send");
return -1;
}
return 0;
}
int do_login(int newfd,sqlite3* db,MSG msg){
char sql[128]="";
char **pres=NULL;
int row,column;
//查询是否是用户名输入错误
sprintf(sql,"select * from user where username=\"%s\";",msg.username);
char* errmsg = NULL;
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(0==row){
printf("[%s]用户名输入错误\n",msg.username);
msg.type = 'F';
strcpy(msg.text,"用户名输入错误");
}
else{
sqlite3_free_table(pres);
//查询是否是密码输入错误
sprintf(sql,"select * from user where username=\"%s\" and password=\"%s\";",msg.username,msg.password);
char* errmsg = NULL;
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(0==row){
printf("[%s]密码输入错误\n",msg.username);
msg.type = 'F';
strcpy(msg.text,"密码输入错误");
}
else{
sqlite3_free_table(pres);
//查询用户是否已经在线
sprintf(sql,"select * from user where username=\"%s\" and password=\"%s\" and flag=\"%c\";",msg.username,msg.password,'N');
char* errmsg = NULL;
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(0==row){
printf("[%s]用户在线\n",msg.username);
msg.type = 'F';
strcpy(msg.text,"用户已在线");
}
else{
//登录成功
msg.type = 'T';
printf("[%s]登录成功\n",msg.username);
strcpy(msg.text,"登录成功");
//将用户上线信息存入数据库
sprintf(sql,"update user set flag=\"%c\" where username=\"%s\";",'Y',msg.username);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
}
}
}
//发送给客户端
if(send(newfd,&msg,sizeof(msg),0) < 0)
{
ERR_MSG("send");
return -1;
}
sqlite3_free_table(pres);
return 0;
}
int do_select(int newfd,sqlite3* db,MSG msg){
char sql[256]="";
char **pres=NULL;
int row,column;
//查询dict表中用户查的单词的意思
sprintf(sql,"select * from dict where word=\"%s\";",msg.text);
char* errmsg = NULL;
if(sqlite3_get_table(db, sql, &pres, &row,&column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
printf("[%s]查询成功\n",msg.username);
//将查到的单词和意思发给用户
sprintf(msg.text,"%s\t%s",pres[2],pres[3]);
if(-1 == send(newfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
//将查到的单词和意思和当时的时间存入历史记录表中
char ti[30] = "";
time_t t = time(NULL);
struct tm *info = NULL;
info = localtime(&t);
sprintf(ti,"%d-%02d-%02d %02d:%02d:%02d",info->tm_year+1900, info->tm_mon+1, info->tm_mday,info->tm_hour, info->tm_min, info->tm_sec);
sprintf(sql,"insert into \"%s\" values(\"%s\",\"%s\",\"%s\");",msg.username,pres[2],pres[3],ti);
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
sqlite3_free_table(pres);
return 0;
}
int do_history(int newfd,sqlite3* db,MSG msg){
char sql[256]="";
char buf[128]="";
char **pres=NULL;
int row,column;
//查询用用户的用户名创出的表中的所有记录
sprintf(sql,"select * from \"%s\";",msg.username);
char* errmsg = NULL;
if(sqlite3_get_table(db, sql, &pres, &row,&column, &errmsg) != SQLITE_OK)
{
fprintf(stderr, "__%d__ sqlite3_get_table:%s\n", __LINE__, errmsg);
return -1;
}
bzero(msg.text,sizeof(msg.text));
//将查到的单词和意思和当时的时间拼在一起发给客户端
for(int i=0; i<(row+1)*column; i+=3)
{
sprintf(buf,"%s\t%s\t%s\n",pres[i],pres[i+1],pres[i+2]);
strcat(msg.text,buf);
}
if(send(newfd,&msg,sizeof(msg),0) < 0)
{
ERR_MSG("send");
return -1;
}
printf("[%s]的历史记录查询成功\n",msg.username);
sqlite3_free_table(pres);
return 0;
}
int do_exit(sqlite3* db,MSG msg){
char sql[128]="";
char *errmsg=NULL;
//将用户下线信息存入数据库
sprintf(sql,"update user set flag=\"%c\" where username=\"%s\";",'N',msg.username);
if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK){
fprintf(stderr, "__%d__ sqlite3_exec:%s\n", __LINE__, errmsg);
return -1;
}
printf("[%s]已下线\n",msg.username);
return 0;
}
server.c
#include "Ser.h"
int main(int argc, const char *argv[])
{
//用信号回收僵尸进程
if(signal(SIGCHLD,handler)==SIG_ERR){
ERR_MSG("signal");
return -1;
}
//如果没有导入dict.txt,先导入
printf("检查字典是否已经导入数据库...\n");
sleep(1);
if(!access("my.db",F_OK)){
printf("已导入数据库\n");
}
else{
printf("未导入,正在导入中...\n");
dicttosql();
}
//创建流式套接字:socket
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(-1 == sfd){
ERR_MSG("socket");
return -1;
}
//服务器信息地址结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //服务器PORT
sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
//绑定服务器IP和端口号:bind
if(-1 == bind(sfd,(struct sockaddr*)&sin,sizeof(sin))){
ERR_MSG("bind");
return -1;
}
//将套接字转化为被动监听状态:listen
if(-1 == listen(sfd,128)){
ERR_MSG("listen");
return -1;
}
struct sockaddr_in cin;
socklen_t addrlen=sizeof(cin);
MSG msg;
while(1){
//获取一个已经完成的客户端信息,生成一个新的文件描述符:accept
int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(-1 == newfd){
ERR_MSG("accept");
return -1;
}
//创建进程
pid_t pid=fork();
if(0 == pid){
close(sfd);
//子进程接收从客户端发来的数据,并做处理
do_recv(newfd);
exit(0);
}
close(newfd);
}
close(sfd);
return 0;
}
客户端:
Cli.h
#ifndef __CLI_C__
#define __CLI_C__
#include <myhead.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"__%d__:",__LINE__);\
perror(msg);\
}while(0)
//用于客户端与服务器传输的结构体
typedef struct {
char type; //协议
char username[20];
char password[20];
char text[128];
}MSG;
#define PORT 8888 //端口号
#define IP "127.0.0.1" //本地主机地址
//注册函数
int do_register(int cfd);
//登录函数
int do_login(int cfd);
//查询函数
int do_select(int cfd,char *name);
//历史记录函数
int do_history(int cfd,char *name);
//退出登录函数
int do_exit(int cfd,char *name);
//退出函数
int do_quit(int cfd);
#endif
Cli.c
#include "Cli.h"
//注册函数
int do_register(int cfd){
MSG msg;
msg.type='R';
printf("请输入用户名>>>");
fgets(msg.username,sizeof(msg.username),stdin); //终端输入用户名
msg.username[strlen(msg.username)-1] = 0;
printf("请输入密码>>>");
fgets(msg.password,sizeof(msg.password),stdin); //终端输入密码
msg.password[strlen(msg.password)-1] = 0;
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
if(-1 == recv(cfd,&msg,sizeof(msg),0))
{
ERR_MSG("recv");
return -1;
}
if(msg.type == 'T') //注册成功
{
printf("%s\n",msg.text);
}
else if(msg.type == 'F') //注册失败
{
printf("%s\n",msg.text);
}
return 0;
}
//登录函数
int do_login(int cfd){
int flag=1; //用于判断退出登录的标示
MSG msg;
msg.type='L';
printf("请输入用户名>>>");
fgets(msg.username,sizeof(msg.username),stdin); //终端输入用户名
msg.username[strlen(msg.username)-1] = 0;
printf("请输入密码>>>");
fgets(msg.password,sizeof(msg.password),stdin); //终端输入密码
msg.password[strlen(msg.password)-1] = 0;
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
if(-1 == recv(cfd,&msg,sizeof(msg),0))
{
ERR_MSG("recv");
return -1;
}
printf("%s\n",msg.text);
if(msg.type == 'F') //登录失败
{
return -1;
}
while(1){
system("clear");
printf("**********************\n");
printf("********1.查询********\n");
printf("******2.历史记录******\n");
printf("******3.退出登录******\n");
printf("**********************\n");
int choose2;
printf("请选择>>>");
scanf("%d",&choose2);
while(getchar()!=10);
switch(choose2){
case 1:
do_select(cfd,msg.username);
break;
case 2:
do_history(cfd,msg.username);
break;
case 3:
flag=do_exit(cfd,msg.username);
break;
default:
printf("输入有误,请重新输入\n");
}
if(flag==0)
{
break;
}
printf("任意字符清屏>>>");
while(getchar()!=10);
}
return 0;
}
//查询函数
int do_select(int cfd,char *name){
MSG msg;
msg.type='S';
strcpy(msg.username,name);
while(1){
printf("请输入要翻译的词(输入Q结束查询)>>>");
fgets(msg.text,sizeof(msg.text),stdin);
msg.text[strlen(msg.text)-1] = 0;
if(!strcmp(msg.text,"Q"))//退出查询
{
break;
}
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
if(-1 == recv(cfd,&msg,sizeof(msg),0))
{
ERR_MSG("recv");
return -1;
}
printf("%s\n",msg.text);
}
return 0;
}
//历史记录函数
int do_history(int cfd,char *name){
MSG msg;
msg.type='H';
strcpy(msg.username,name);
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
if(recv(cfd,&msg,sizeof(msg),0) < 0)
{
ERR_MSG("recv");
return -1;
}
printf("%s",msg.text);
return 0;
}
//退出登录函数
int do_exit(int cfd,char *name){
MSG msg;
msg.type='E';
strcpy(msg.username,name);
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
return 0;
}
//退出函数
int do_quit(int cfd){
MSG msg;
msg.type='Q';
if(-1 == send(cfd,&msg,sizeof(msg),0)){
ERR_MSG("send");
return -1;
}
return 0;
}
client.c
#include "Cli.h"
int main(int argc, const char *argv[])
{
//创建流式套接字:socket
int cfd=socket(AF_INET,SOCK_STREAM,0);
if(-1 == cfd){
ERR_MSG("socket");
return -1;
}
//服务器信息地址结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT); //服务器PORT
sin.sin_addr.s_addr = inet_addr(IP); //服务器IP
//与服务器建立连接:connect
if(-1 == connect(cfd,(struct sockaddr*)&sin,sizeof(sin))){
ERR_MSG("connect");
return -1;
}
int choose=0;
int flag=0;
while(1){
system("clear");
printf("**********************\n");
printf("********1.注册********\n");
printf("********2.登录********\n");
printf("********3.退出********\n");
printf("**********************\n");
printf("请选择>>>");
scanf("%d",&choose);
while(getchar()!=10);
switch(choose){
case 1:
do_register(cfd);
break;
case 2:
do_login(cfd);
break;
case 3:
flag=1;
do_quit(cfd);
break;
default:
printf("输入有误,请重新输入\n");
}
if(flag==1){
break;
}
printf("任意字符清屏>>>");
while(getchar()!=10);
}
//关闭套接字文件描述符
close(cfd);
return 0;
}