(五)linux下c语言实现在线词典

一.客户端代码:

#include
#include
#include           /* 套接字用的头文件*/
#include
#include
#include //inet_addr ip地址格式的转换
#include
#include
#include


#define R 1//user - register
#define L 2//user - login
#define Q 3//user - query
#define H 4//user - history

//定义通信双方的信息结构体
#define N 32
typedef struct
{
    int type;
    char name[N];
    char data[256];
}MSG;

/***************************************
**argc 表示参数个数 argv表示具体参数****
****************************************/

int do_register(int sockfd,MSG *msg) //需要文件描述符,传输结构体
{
    msg->type = R;
    printf("input name:");
    scanf("%s",msg->name);
    getchar();
    printf("input password:");
    scanf("%s",msg->data);
    if(send(sockfd,msg,sizeof(MSG),0)<0)
    {
        printf("fail to send.\n");
        return -1;
    }
    if(recv(sockfd,msg,sizeof(MSG),0)<0)
    {
        printf("fail to recv...\n");
        return -1;
    }
    //ok! or usr alread exist
    printf("%s\n",msg->data);
    return 0;
}
int do_login(int sockfd,MSG *msg)
{
    
    msg->type = L;
    printf("input name:");
    scanf("%s",msg->name);
    getchar();
    printf("input password:");
    scanf("%s",msg->data);
    if(send(sockfd,msg,sizeof(MSG),0)<0)//发送给服务器
    {
        printf("fail to send.\n");
        return -1;
    }
    if(recv(sockfd,msg,sizeof(MSG),0)<0)//从服务器接受
    {
        printf("fail to recv...\n");
        return -1;
    }
    if(strncmp(msg->data,"OK",3) == 0)
    {
        printf("login ok\n");
        return 1;
    }
    else
    {
        printf("%s",msg->data);
    }
    return 0;//登录成功
}
int do_query(int sockfd,MSG *msg)
{
    msg->type = Q;
    puts("-------------------");
    while(1)
    {
        printf("Input word:");
        scanf("%s",msg->data);
        getchar();
        //客户端输入# 返回上级菜单。
        if(strncmp(msg->data,"#",1)==0)
            break;
        //将要查询的单词发送给服务器
        if(send(sockfd,msg,sizeof(MSG),0)<0)
        {
            printf("fail to send.\n");
            return -1;
        }
        //等待接受服务器,传递回来的单词的注释信息
        if(recv(sockfd,msg,sizeof(MSG),0)<0)
        {
            printf("fail wo recv.\n");
            return -1;
        }
        printf("%s\n",msg->data);
    }
    return 0;
}
int do_history(int sockfd,MSG *msg)
{
    msg->type = H;
    send(sockfd,msg,sizeof(MSG),0);
    //接受服务器 传递回来的历史信息
    while(1)
    {
        recv(sockfd,msg,sizeof(MSG),0);
        if(msg->data[0] == '\0')
            break;
        //输出历史信息
        printf("%s\n",msg->data);
    }
    return 0;
}


// ./server 192.168.1.9 10000 ip地址用ifconfig查询
int main(int argc,const char *argv[])
{
    int n;
    MSG msg;
    int sockfd;//定义一个文件描述符,是在查看socket函数之后发现返回值是int
    struct sockaddr_in serveraddr; //网络信息填充的结构体,表示服务器地址。
    if(argc != 3)//判断传参数个数
    {
        printf("Usage:%s serverip port.\n",argv[0]);
        return -1;//参数输出错误
    }

    //创建流式套接字
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) //表示失败AF_INET表示IPV4,SOCK_STREAM.
    {
        perror("fail to socket");//创建套接字失败提醒
        return -1;//失败之后直接退出
    }
    //网络信息填充
    bzero(&serveraddr,sizeof(serveraddr));//链接服务器,先对服务器清空
    serveraddr.sin_family = AF_INET;//填充结构体成员(查一下?)
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//传输入的ip地址
    serveraddr.sin_port = htons(atoi(argv[2]));//htons将本地数据转换为网络数据 atoi是将字符串转化为整数 10000是字符串
    //链接服务器 调用connect函数
    if(connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0) //1.sockaddr 和sockaddr_in 的区别以及为什么强制转换
    {
        perror("fail to connect");
        return -1;
    }
    //一级菜单
    while(1)
    {
        printf("****************************************************\n");
        printf("* 1.register        2.login       3.quit           *\n");
        printf("****************************************************\n");
        printf("Please choose:");

        scanf("%d",&n);
        getchar();//每次输入玩有个垃圾字符去掉
        switch(n)
        {
            case 1:
                do_register(sockfd,&msg);
                break;
            case 2:
                if(do_login(sockfd,&msg)==1)
                {
                    goto next;
                }
                break;
            case 3:
                close(sockfd);//退出的话是把文件描述符关闭
                exit(0);//正确退出
                break;
            default:
                printf("Invalid data cmd.\n");
        }

    }
next :
    while(1)
    {
        printf("***********************************************\n");
        printf("* 1.query_word     2.history_record      3.quit\n");
        printf("***********************************************\n");
        printf("Please choose:");
        scanf("%d",&n);
        getchar();

        switch(n)
        {
            case 1:
                do_query(sockfd,&msg);
                break;
            case 2:
                do_history(sockfd,&msg);
                break;
            case 3:
                close(sockfd);
                exit(0);
                break;
            default:
                printf("Invalid data cmd.\n");//重新输入就完了 所以不用break
        }
    }


    return 0;
}


2.服务器代码:



#include
#include
#include           /* 套接字用的头文件*/
#include
#include
#include //inet_addr ip地址格式的转换
#include
#include
#include
#include
#include

#define R 1//user - register
#define L 2//user - login
#define Q 3//user - query
#define H 4//user - history

#define DATABASE "my.db"
//定义通信双方的信息结构体
#define N 32
typedef struct
{
    int type;
    char name[N];
    char data[256];
}MSG;

/***************************************
**argc 表示参数个数 argv表示具体参数****
****************************************/

void do_register(int acceptfd,MSG *msg,sqlite3 *db) //需要文件描述符,传输结构体
{
    char *errmsg;
    char sql[128];
    sprintf(sql,"insert into usr values('%s','%s');",msg->name,msg->data);
    printf("%s\n",sql);
    if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
    {
        printf("%s\n",errmsg);
        strcpy(msg->data,"usr name already exist.");
    }
    else
    {
        printf("client register ok!\n");
        strcpy(msg->data,"OK!");
    }
    if(send(acceptfd,msg,sizeof(MSG),0)<0)
    {
        perror("fail to send");
        return;
    }
    return;
}
int do_login(int acceptfd,MSG *msg,sqlite3 *db)
{
    char sql[128] = {};
    char *errmsg;
    int nrow;
    int ncloumn;
    char **resultp;
    sprintf(sql,"select *from usr where name = '%s' and pass = '%s';",msg->name,msg->data);
    printf("%s\n",sql);
    if(sqlite3_get_table(db,sql,&resultp,&nrow,&ncloumn,&errmsg)!=SQLITE_OK)
    {
        printf("%s\n",errmsg);
        return -1;
    }
    else
    {
        printf("get table ok!\n");
    }
    //查询成功,数据库有此用户
    if(nrow == 1)
    {
        strcpy(msg->data,"OK");
        send(acceptfd,msg,sizeof(MSG),0);
        return 1;
    }
    if(nrow == 0)//密码或者用户名错误
    {
        strcpy(msg->data,"usr/passwd wrong.");
        send(acceptfd,msg,sizeof(MSG),0);
        return 0;
    }
    return 0;//登录成功
}
int do_searchword(int acceptfd,MSG *msg,char word[])
{
    FILE *fp;
    int len = 0;
    char temp[512];
    int result;
    char *p;
    //打开文件,读取文件,进行比对
    if((fp = fopen("dict.txt","r"))==NULL)
    {
        perror("fail to fopen\n");
        strcpy(msg->data,"Failed to open dict.txt\n");
        send(acceptfd,msg,sizeof(MSG),0);
        return -1;
    }
    //打印出客户端要查询的单词
    len = strlen(word);
    printf("%s,len = %d\n",word,len);
    //读文件来查询单词
    while(fgets(temp,512,fp)!=NULL)
    {
        result = strncmp(temp,word,len);
        if(result > 0)
        {
            continue;
        }
        if(result < 0 || temp[len] !=' ')
        {
            break;
        }
        //表示找到查询的单词
        p = temp + len;
        while(*p == ' ')
        {
            p++;
        }
        //找到注释,跳跃过所有空格
        strcpy(msg->data,p);
        printf("%s\n",msg->data);
        send(acceptfd,msg,sizeof(MSG),0);
        //拷贝完毕之后应该关闭文件
        fclose(fp);
        return 1;
    }
    strcpy(msg->data,"word cant be found!");
    fclose(fp);
    return 0;
}

int get_date(char *date)
{
    time_t t;
    struct tm *tp;
    time(&t);
    //进行时间格式转换
    localtime(&t);
    sprintf(date,"%d-%d-%d %d:%d:%d",tp->tm_year+1990,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec);
    return 0;
}


int do_query(int acceptfd,MSG *msg,sqlite3 *db)
{
    char word[64];
    int found = 0;
    char date[128];
    char sql[128];
    char *errmsg;
    //拿出msg结构体中要查询的单词
    strcpy(word,msg->data);
    found = do_searchword(acceptfd,msg,word);
    //找到单词,此时应该将用户名时间和单词插入到历史记录表中去
    if(found == 1)
    {
        //获取系统时间
        get_date(date);
        sprintf(sql,"insert into record values('%s','%s','%s');",msg->name,date,word);
        printf("%s\n",sql);

        if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
        {
            printf("%s\n",errmsg);
            return -1;
        }

    }
    else//表示没有找到
    {
        strcpy(msg->data,"Not found!");
    }
    //将查询的结果,发送给客户端
    send(acceptfd,msg,sizeof(MSG),0);
    //将查询的结果发送给客户端
    return 0;
}
//得到查询结果,并且需要将历史记录发送给客户端
int history_callback(void* arg,int f_num,char**f_value,char ** f_name)
{
    int acceptfd;
    MSG msg;
    acceptfd = *((int *)arg);
    sprintf(msg.data,"%s , %s",f_value[1],f_value[2]);
    send(acceptfd,&msg,sizeof(MSG),0);
    return 0;
}
int do_history(int acceptfd,MSG *msg,sqlite3 *db)
{
    char sql[128] = {};
    char *errmsg;
    sprintf(sql,"select * from record where name = '%s';",msg->name);
    //查询数据库;
    if(sqlite3_exec(db,sql,history_callback,(void *)&acceptfd,&errmsg)!=SQLITE_OK)
    {
        printf("%s\n",errmsg);
    }
    else
    {
        printf("Query record done.\n");
    }
    //所有的记录查询完毕之后,给客户端发出结束信息
    msg->data[0] = '\0';
    send(acceptfd,msg,sizeof(MSG),0);
    return 0;
}



int do_client(int acceptfd,sqlite3 *db);

// ./server 192.168.1.9 10000 ip地址用ifconfig查询
int main(int argc,const char *argv[])
{
    int n;
    pid_t pid;
    MSG msg;
    sqlite3 *db;
    int acceptfd;
    int sockfd;//定义一个文件描述符,是在查看socket函数之后发现返回值是int
    struct sockaddr_in serveraddr; //网络信息填充的结构体,表示服务器地址。
    if(argc != 3)//判断传参数个数
    {
        printf("Usage:%s serverip port.\n",argv[0]);
        return -1;//参数输出错误
    }
    //打开数据库
    if(sqlite3_open(DATABASE,&db)!=SQLITE_OK)
    {
        printf("%s\n",sqlite3_errmsg(db));
        return -1;
    }
    else
    {
        printf("open DATABASE success\n");
    }

    //创建流式套接字
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) //表示失败AF_INET表示IPV4,SOCK_STREAM.
    {
        perror("fail to socket");//创建套接字失败提醒
        return -1;//失败之后直接退出
    }
    //网络信息填充
    bzero(&serveraddr,sizeof(serveraddr));//链接服务器,先对服务器清空
    serveraddr.sin_family = AF_INET;//填充结构体成员(查一下?)
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//传输入的ip地址
    serveraddr.sin_port = htons(atoi(argv[2]));//htons将本地数据转换为网络数据 atoi是将字符串转化为整数 10000是字符串
    //绑定函数
    if(bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr))<0)
    {
        perror("fail to bind.\n");
        return -1;
    }
    
    //将套接字设置为监听模式,等待客户端链接请求到来
    if(listen(sockfd,5)<0)
    {
        printf("fail to listen.\n");
        return -1;    
    }

    //处理僵尸进程
    signal(SIGCHLD,SIG_IGN);

    //一级菜单
    while(1)
    {
        //accept接受连接请求 fork创建子进程通信
        if((acceptfd = accept(sockfd,NULL,NULL))<0)
        {
            perror("fail to accept");
            return -1;
        }
        if((pid = fork())<0)
        {
            perror("fail to fork");
            return -1;
        }
        else if(pid == 0)//儿子进程
        {
            
            //处理客户端具体消息
            close(sockfd);//监听套接字
            do_client(acceptfd,db);

        }
        else//父亲进程,用来接受客户端的请求
        {
            close(acceptfd);
        }
        
    }


    return 0;
}

int do_client(int acceptfd,sqlite3 *db)
{
    MSG msg;
    while(recv(acceptfd,&msg,sizeof(msg),0) > 0)
    {
        printf("type:%d\n",msg.type);
        switch(msg.type)
        {
        case R:
            do_register(acceptfd,&msg,db);
            break;
        case L:
            do_login(acceptfd,&msg,db);
            break;
        case Q:
            do_query(acceptfd,&msg,db);
            break;
        case H:
            do_history(acceptfd,&msg,db);
            break;
        default:
            printf("Invalid data msg.\n");
        }
    }
    printf("client exit.\n");
    close(acceptfd);
    exit(0);
    return 0;
}










































你可能感兴趣的:(Linux,C)