服务器端:
Ser.h
#ifndef __SER_H__
#define __SER_H__
#include
#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;itm_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
#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;
}