您的位置:首页 > 运维架构 > Linux

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

2017-08-14 16:34 316 查看
一.客户端代码:

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>          /* 套接字用的头文件*/

#include <sys/socket.h>

#include <strings.h>

#include <netinet/in.h>//inet_addr ip地址格式的转换

#include <arpa/inet.h>

#include <unistd.h>

#include <string.h>

#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
;

    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 <stdio.h>

#include <stdlib.h>

#include <sys/types.h>          /* 套接字用的头文件*/

#include <sys/socket.h>

#include <string.h>

#include <netinet/in.h>//inet_addr ip地址格式的转换

#include <arpa/inet.h>

#include <unistd.h>

#include <sqlite3.h>

#include <signal.h>

#include <time.h>

#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
;

    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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息