Linux 网络编程6 在线词典

Linux 网络编程6 在线词典

项目介绍

该项目为HQ嵌入式Linux应用项目,主要运用知识:Sqlite3 数据库基本操作,TCP/IP多并发编程,文件IO, 。
程序流程:
在这里插入图片描述

项目代码

client端
在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define N 64
#define R  1        //register
#define L  2        //log_in
#define Q  3        //query
#define H  4        //history

typedef struct{
    int type;
    char name[N];
    char data[256];     //save password of word
}MSG;

void do_register(int *socketfd, MSG * msg);
int do_login(int *socketfd, MSG * pmsg);
void do_query(int *socketfd, MSG * pmsg);
void do_history();


/* ./server  IP地址 端口号 */
int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("please input the ip_addr and port \n");
        return 0;
    }

    int socketfd;
    struct sockaddr_in myaddr;
    int cmd;
    MSG msg;
    bzero(&msg, sizeof(msg));

    if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket fail");
        exit(-1);
    }
    printf("%s \n%s\n", argv[1], argv[2]);

    bzero(&myaddr, sizeof(myaddr));

    myaddr.sin_family =  AF_INET;
    inet_pton(AF_INET,argv[1],(void *)&myaddr.sin_addr.s_addr);
    myaddr.sin_port = htons(atoi(argv[2]));

    if((connect(socketfd,(struct sockaddr *)&myaddr,sizeof(myaddr))) < 0)
    {
        perror("connect fail");
        exit(-1);
    }

    while(1)
    {
        printf("**********************************\n");
        printf("* 1: register  2: login  3: quit *\n");
        printf("**********************************\n");
        printf("Your cmd: ");
        scanf("%d",&cmd);
        getchar();                     //delete '\n'

        switch(cmd)
        {
            case 1:
                do_register(&socketfd, &msg);
                break;
            case 2:
                if(do_login(&socketfd, &msg) == 1)
                if(cmd == 2)
                {
                    goto next;		//进入二级菜单
                }
                break;
            case 3:
                close(socketfd);
                exit(0);
                break;
            default:
                printf("invalid input !\n");
                break;
        }

    }
    next:
        while(1)
        {
            printf("***********************************************\n");
            printf("* 1: query_word  2: history_record  3: quit   *\n");
            printf("***********************************************\n");
            printf("Your cmd: ");
            scanf("%d",&cmd);
            getchar();
            switch (cmd)
            {
                case 1:
                    do_query(&socketfd, &msg);
                    break;
                case 2:
                    do_history(&socketfd, &msg);
                    break;
                case 3:
                    close(socketfd);
                    exit(0);
                    break;
                default:
                    printf("invalid input! \n");
                    break;
            }
        }

    return 0;
}

void do_register(int *socketfd, MSG * pmsg)
{
    int len_msg = sizeof(*pmsg);
    pmsg->type = R;
    printf("username: ");
    scanf("%s", pmsg->name);
    getchar();
    printf("password: ");
    scanf("%s",pmsg->data);
    send(*socketfd, pmsg, len_msg, 0);

    // printf("username %s\n",pmsg->name);
    // printf("password %s\n", pmsg->data);
    recv(*socketfd, pmsg, len_msg, 0);
    printf("%s\n",pmsg->data);
}

int do_login(int *socketfd, MSG * pmsg)
{
    int len_msg = sizeof(*pmsg);
    bzero(pmsg,len_msg);
    pmsg->type = L;
    printf("username: ");
    scanf("%s",pmsg->name);
    getchar();
    printf("password: ");
    system("stty -echo");	//隐藏输入
    scanf("%s",pmsg->data);
    system("stty echo");	//隐藏输入
    getchar();

    //printf("%s\n%s\n",pmsg->name,pmsg->data);
    if((send(*socketfd, pmsg, len_msg, 0)) < 0)
    {
        perror("send fail");
        exit(-1);
    }
    
    if(recv(*socketfd,pmsg,len_msg,0) < 0)
    {
        perror("recv fail");
        exit(-1);
    }

    if(!strncmp(pmsg->data,"OK", strlen("OK")))
    {
        printf("Login success!\n");
        return 1;
    }
    else
    {
        printf("Password or username error \n");
        return 0;
    }

}

void do_query(int *socketfd, MSG * pmsg)
{
    char word[64]= {0};
    int len_msg = sizeof(*pmsg);
    //bzero(pmsg,sizeof(*pmsg));
    pmsg->type = Q;
    while(1)
    {
        printf("Enter a word you want to search for('#' to end): ");
        scanf("%s", pmsg->data);
        getchar();
        strcpy(word,pmsg->data);
        if(!strncmp(pmsg->data,"#",2))
        {
            printf("quert end! \n");
            break;
        }
        if(send(*socketfd, pmsg, len_msg, 0) < 0)
        {
            perror("send fail");
            exit(-1);
        }
        if(recv(*socketfd,pmsg,len_msg,0) < 0)
        {
            perror("recv fail");
            exit(-1);
        }
        /*结果输出需要美化*/
        printf("\n");
        printf("%s\n ",word);
        printf("%10s \n",pmsg->data);
    }
}

void do_history(int *socketfd, MSG * pmsg)
{
    int len_msg = sizeof(*pmsg);
    pmsg->type = H;
    memset(pmsg->data, 0 ,sizeof(pmsg->data));
    if(send(*socketfd, pmsg, len_msg, 0) < 0)
    {
        perror("send fail");
        exit(-1);
    }
    while (1)
    {   
        if(recv(*socketfd,pmsg,len_msg,0) < 0)
        {
            perror("recv fail");
            exit(-1);
        }
        //printf("msg.data : %s\nmsg.name: %s",pmsg->data, pmsg->name);
        if(!strncmp(pmsg->data,"query_over",10))
        {
            printf("query histoy over! \n");
            break;
        }
        printf("%s \n",pmsg->data);
    }
    
}

server端

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "sqlite3.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>


#define N 64
#define R  1        //register
#define L  2        //log_in
#define Q  3        //query
#define H  4        //history
#define Netprot  端口号
#define Netip   "IP地址"
#define BACKLOG  5

typedef struct{
    int type;
    char name[N];
    char data[256];     //save password of word
}MSG;

void do_register(int* recvfd,sqlite3 * db, MSG * pmsg);
void do_login(int* recvfd, sqlite3 * db, MSG * pmsg);
void do_query(int* recvfd, sqlite3 * db, MSG * pmsg);
void do_history();
void cil_data_handle(int signum);


int main(int argc, char* argv[])
{
    /*
        signal 回收僵尸进程
    */
    signal(SIGCHLD, cil_data_handle); 
    int socketfd;
    sqlite3 * mysql;
    struct sockaddr_in server_addr;

    if((socketfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
    {
        perror("socket fail");
        exit(-1);
    }
    if(sqlite3_open("info.db", &mysql) != SQLITE_OK)
    {
        printf("sqlite3 open fail %s \n",sqlite3_errmsg(mysql));
        exit(-1);
    }

    /* 快速复用 设置*/
    int b_reuse = 1;
    setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));

    server_addr.sin_family =  AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(Netip);
    server_addr.sin_port = htons(Netprot);

    if(bind(socketfd,(struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind fail");
        exit(-1);
    }

    if(listen(socketfd,BACKLOG) < 0)
    {
        perror("listen fail");
        exit(-1);
    }

    int recvfd;
    pid_t pid;
    MSG msg;
    while(1)
    { 
        /*
            可创建struct sockaddr 变量保存连接客户端的ip信息
        */
        if((recvfd = accept(socketfd,NULL,NULL)) < 0 )
        {
            perror("accept fail");
            exit(-1);
        }
        pid = fork();
        if(pid < 0)
        {
            perror("fork fail");
            exit(-1);
        }
        else if(pid == 0)           //child process
        {
            printf("new client connet\n");
            close(socketfd);
            while(recv(recvfd, &msg, sizeof(msg), 0))
            {
                //printf("type = %d\n", msg.type);
               switch(msg.type)
                {
                    case R:
                        do_register(&recvfd ,mysql, &msg);
                        break;
                    case L:
                        do_login(&recvfd ,mysql, &msg);
                        break;
                    case Q:
                        do_query(&recvfd ,mysql, &msg);
                        break;
                    case H:
                        do_history(&recvfd ,mysql, &msg);
                        break;
                }
            }
            printf("client exit \n");
            close(recvfd);
            return 0;
        }
        else                        //father process
        {
            close(recvfd);
        }
    }
    
    return 0;
}

void do_register(int* recvfd, sqlite3 * db, MSG * pmsg)
{
    MSG msg = *pmsg;
    int len_msg = sizeof(msg);
    //printf("do_register :server\n");
    //printf("recv username : %s \n",pmsg->name);
    //printf("recv password %s \n", pmsg->data);
    char sql[400] = {0};
    char *errmsg;
    sprintf(sql,"insert into user values('%s', '%s');",pmsg->name, pmsg->data);
    if((sqlite3_exec(db,sql,NULL,NULL,&errmsg)) !=  SQLITE_OK)
    {
        printf("sqlite3 fail: %s \n",errmsg);
        strcpy(pmsg->data,"user is already");
    }
    else
    {
        strcpy(pmsg->data,"regiseter success!");
    }
    if(send(*recvfd, pmsg, len_msg, 0) < 0)
    {
        perror("send fail");
        exit(-1);
    }
}

void do_login(int* recvfd, sqlite3 * db, MSG * pmsg)
{
    printf("do_login :server\n");
    // printf("recv username : %s \n",pmsg->name);
    // printf("recv password : %s \n", pmsg->data);    
    int len_msg = sizeof(*pmsg);
    char sql[400]={0};
    char ** result;
    int row;
    int cloumn;
    char * errmsg;

    sprintf(sql,"select * from user where username='%s' and password='%s';",pmsg->name,pmsg->data);    
    if((sqlite3_get_table(db, sql, &result, &row, &cloumn, &errmsg)) != SQLITE_OK)
    {
        printf("get_table fail %s \n",errmsg);
        exit(-1);
    }
    if(row == 1)
    {
        //用户名和密码正确
        strncpy(pmsg->data, "OK",3);        //千万不能使用sizeof("OK")会出现stack smashing detected 
        if(send(*recvfd,pmsg,len_msg,0) < 0 )
        {
            perror("Lsend fail");
            exit(-1);
        }
        sqlite3_free_table(result);

    }
    else
    {
        //用户名和密码有误
        strncpy(pmsg->data,"ERR",len_msg);
        if(send(*recvfd,pmsg,len_msg,0) < 0)
        {
            perror("Lsend fail");
            exit(-1);            
        }
        sqlite3_free_table(result);
    }
    
}

int do_searchword(MSG * pmsg)
{
    printf("searchword begin!\n");
    //pmsg->data 要查询内容
    FILE *fp;
    int ret;
    char temp[512] = {0};

    char word[64] = {0};
    strcpy(word,pmsg->data);
    //printf("word = %s", word);
    
    char * p;
    int len = strlen(word);
    if((fp = fopen("dict.txt","r")) == NULL)
    {
        perror("fopne fail");
        exit(-1);
    }
    /* 按行搜索 */
    while(fgets(temp,sizeof(temp)-1,fp) != NULL)    
    {
        printf("find process %s \n",temp);
        ret = strncmp(pmsg->data,temp, len);
        //printf("ret = %d \n", ret);
        if(ret > 0)
        {
            //没有找到
            printf("continue \n");
            continue;
        }     
        if(ret == 0 && temp[len] == ' ')
        {
            //找到了
            printf("find the word %s \n",pmsg->data);
            break; 
        }
        else        //ret < 0
        {
            printf("There is no such word \n");
            return -1;
        }
    }
    p = temp + len;             //定义文件指针,用于提取单词后的解释 

    while(*p == ' ')            //abandonment      n.  abandoning 将指针移动到解释字符串的头部
    {
        p++;
    }
    strcpy(pmsg->data, p);
    //printf("the word means: %s \n",pmsg->data);
    fclose(fp);
    return 1;
}


void do_query(int* recvfd, sqlite3 * db, MSG * pmsg)
{
    printf("do_query :server\n");
    int find;
    int len_msg = sizeof(*pmsg);
    char *word = pmsg->data;
    char *name = pmsg->name;
    MSG query_msg;
    query_msg = *pmsg;
    //recv(*recvfd, pmsg, len_msg, 0);
    find = do_searchword(&query_msg);
    pmsg = &query_msg;
    if(find < 0)
    {
        strcpy(pmsg->data, "Word not found! ");
    }
    send(*recvfd,pmsg,len_msg,0);
    
    //获取当前系统时间
    time_t systime;
    struct tm * rectime;
    char time_string[40]={0};
    char sql[256] = {0};
    char *errmsg;
    time(&systime);
    rectime  = localtime(&systime);
    /*printf("%d-%d-%d %d:%d \n",
             rectime->tm_year+1900, rectime->tm_mon+1, rectime->tm_mday, rectime->tm_hour, rectime->tm_min);
    */
    strftime(time_string,sizeof(time_string),"%Y-%m-%d %H:%M:%S",rectime);
    //printf("date: %s \n",time_string);
    //insert into record values(time, username, word);
    sprintf(sql,"insert into record values('%s','%s','%s');",time_string, name, word);
    if(sqlite3_exec(db,sql,NULL, NULL, &errmsg) != SQLITE_OK)
    {
        printf("sqlite_exec fail %s \n",errmsg);
        exit(-1);
    }


}
int history_callback(void* arg, int columns ,char** fvalue, char** fname)
{   
    //printf("history_callback begin \n");
    MSG msg;
    int * recvfd = (int *)arg;
    //int recvfd = *(int *)arg;
    // printf("fvalue[0]")
    sprintf(msg.data,"%10s|%10s|%10s",fvalue[0],fvalue[1],fvalue[2]);
    //printf("%s\n",msg.data);
    if(send(*recvfd, &msg, sizeof(MSG), 0) < 0 )
    {
        perror("send fail");
        exit(-1);
    }
    return 0;
}

void do_history(int* recvfd, sqlite3 * db, MSG * pmsg)
{
    printf("do_history : server\n");
    
    char sql[256];
    sprintf(sql,"select * from record where username='%s';",pmsg->name);
    char * errmsg;
    //select * from record
    if((sqlite3_exec(db, sql, history_callback, (void *)recvfd, &errmsg)) != SQLITE_OK)
    {
        printf("sqlite_exec fail %s \n",errmsg);
        exit(-1);
    }

    // 所有的记录查询发送完毕之后,给客户端发出一个结束信息
	strcpy(pmsg->data,"query_over");
	send(*recvfd, pmsg, sizeof(MSG), 0);


}

void cil_data_handle(int signum)
{
    if(signum == SIGCHLD)
    {
        waitpid(-1,NULL,WNOHANG);
    }

}

在这里插入图片描述

效果展示

一级菜单
在这里插入图片描述

查询功能
在这里插入图片描述
历史记录
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值