基于TCP的在线词典

这篇博客介绍了如何利用TCP通信实现一个简单的在线词典应用。包括用户注册、登录、查询单词和历史记录功能。代码示例展示了服务器端如何处理数据库操作,如插入和查询,以及客户端如何发送请求并接收响应。此外,还提到了未来的计划,即实现基于IO多路复用的TCP并发服务器在线词典。
摘要由CSDN通过智能技术生成

基于tcp通信在线词典

1、功能说明

注册 用户名 (唯一编号)和密码
登录 用户名和密码 (比对数据库)
1、查询单词 (输入单词 查询)
2、查询历史记录(查看 用户查询单词情况)
在线词典界面

2、流程图

在这里插入图片描述

在这里插入图片描述

(1)注册功能

在命令终端根据提示信息,输入用户名和密码,将所注册信息添加进数据库。根据程序提示信息,判断用户是否注册成功(添加数据库)。

在这里插入图片描述
代码实现思路:其实代码很简单,客户端根据提示信息输入用户名和密码发送给服务器,服务器执行写数据库操作,将插入数据库提示信息发挥给客户端,回显给用户。
服务器:

int regster(int sockfd, msg_t *msg, sqlite3 *my_db)
{
    char sqlstr[512] = {0};
    int ret = 0;
    //注册执行写数据库操作
    sprintf(sqlstr, "INSERT INTO usr VALUES('%s','%s')", msg->name, msg->txt);
    printf("-----sqlstr:[%s]-----\n", sqlstr);
    //执行插入操作
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, NULL, NULL, NULL)))
    {
        printf("errcode:[%d]   errstr:[%s]\n", ret, sqlite3_errmsg(my_db));
        msg->code = -1;
        snprintf(msg->txt, sizeof(msg->txt), "errcode:[%d]   errstr:[%s]\n", ret, sqlite3_errmsg(my_db));
        send(sockfd, msg, sizeof(*msg), 0);
        return -1;
    }
    snprintf(msg->txt, sizeof(msg->txt), "插入成功\n");
    send(sockfd, msg, sizeof(msg), 0);
}

客户端:

int regster(int sockfd, msg_t *msg)
{
    char name_buff[32] = {0};
    char password[16] = {0};
    msg->code = 1;
    printf("请输入你的名字:");
    fgets(name_buff, sizeof(name_buff), stdin);
    name_buff[strlen(name_buff) - 1] = '\0';

    printf("请输入你的密码:");
    fgets(password, sizeof(password), stdin);
    password[strlen(password) - 1] = '\0';

    strcpy(msg->name, name_buff);
    strcpy(msg->txt, password);

    send(sockfd, msg, sizeof(*msg), 0);
    recv(sockfd, msg, sizeof(*msg), 0);

    if (msg->code == -1)
    {
        printf("用户名已经存在\n");
    }
    else
        printf("注册成功\n");
    system("read -p '请按任意键继续....' var");
    system("clear");
}

(2)登录功能

在命令终端根据提示信息,输入用户名和密码,将所输信息与数据库信息比对。根据程序提示信息,判断用户是否登录成功(条件查找)。

在这里插入图片描述
代码实现思路:客户端根据提示信息输入用户名和密码发送给服务器,服务器执行数据库查询操作,并把查询结果反馈给客户端,客户端根据反馈结果进行相应操作。
服务器:

int login(int sockfd, msg_t *msg, sqlite3 *my_db)
{
    char sqlstr[512] = {0};
    //使用 sqlite3_get_table 查询结果
    char **result = NULL;
    int row = 0;
    int column = 0;
    int ret = 0;

    sprintf(sqlstr, "SELECT * FROM usr WHERE name='%s' AND pass=%s ", msg->name, msg->txt);
    printf("sqlstr=%s\n", sqlstr);
    if (SQLITE_OK != (ret = sqlite3_get_table(my_db, sqlstr, &result, &row, &column, NULL)))
    {
        printf("errcode:[%d]   errstr:[%s]\n", ret, sqlite3_errmsg(my_db));
        // exit(-1);
    }
    if (row == 1)
    {
        strcpy(msg->txt, "登陆成功\n");
        send(sockfd, msg, sizeof(*msg), 0);
    }
    else
    {
        msg->code = -1;
        strcpy(msg->txt, "用户名或者密码有误\n");
        send(sockfd, msg, sizeof(*msg), 0);
    }
}

客户端:

int login(int sockfd, msg_t *msg)
{
    char name_buff[32] = {0};
    char password[16] = {0};
    int sele = 0;
    msg->code = 2;
    printf("请输入你的名字:");
    fgets(name_buff, sizeof(name_buff), stdin);
    name_buff[strlen(name_buff) - 1] = '\0';

    printf("请输入你的密码:");
    fgets(password, sizeof(password), stdin);
    password[strlen(password) - 1] = '\0';

    strcpy(msg->name, name_buff);
    strcpy(msg->txt, password);

    send(sockfd, msg, sizeof(*msg), 0);
    // puts("1");
    recv(sockfd, msg, sizeof(*msg), 0);

    if (msg->code == -1)
    {
        printf("%s\n", msg->txt);
    }
    else
    {
        printf("%s\n", msg->txt);
       
        while (1)
        { 
            showmenu2();
            printf("请选择功能:");
            scanf("%d", &sele);
            getchar();
            switch (sele)
            {
            case 1: //查询
                quary(sockfd, msg);
                break;
            case 2: //查看历史记录
                history(sockfd, msg);
                break;
            case 3:
                printf("返回上一级目录\n");
                goto next;
                // close(fp);
                break;
            }
        }

        //调用另一个函数
    }
next:
    system("read -p '请按任意键继续....' var");
    system("clear");
}
((1))单词查询
在命令端根据提示信息,输入要查询的单词,然后读取文件,查找与之对应的单词词条并显示提示信息或结果在终端命令行。与此同时,将查询时间 用户信息 要查询的单词,一同记录在数据库中方便后续功能调用。

在这里插入图片描述
代码实现思路:在客户端给服务器发出查询请求时,先将查询时间,用户名要查询单词,记录在数据库。因为单词和解释保存在文本文件中,单词和解释只占一行,一行最多300个字节,单词和解释之间至少有一个空格。所以我们用标准io中fgets()函数读取一行内容。依次比较,直到查询到单词发送信息给客户端,或者查询失败发送信息给客户端。客户端根据接受到的信息进行信息处理。
服务器:

int quary(int sockfd, msg_t *msg, sqlite3 *my_db, FILE *fp)
{
    // printf("查询单词\n");
    //查到了发过去 if()
    int len = strlen(msg->txt);
    char temp[300] = {0};
    char *p = temp;
    char sqlstr[512] = {0};
    char timebuf[128]={0};
    int ret = 0;
    time_t *t;
    time(t);
    struct tm * tp= localtime(t);
    sprintf(timebuf, "%d-%d-%d %d:%d:%d",  1900+tp->tm_year,  1+tp->tm_mon,  tp->tm_mday, \
					tp->tm_hour, tp->tm_min, tp->tm_sec);
    //先记录
    sprintf(sqlstr, "INSERT INTO record VALUES('%s','%s','%s')",timebuf, msg->name, msg->txt);
    //printf("-----sqlstr:[%s]-----\n", sqlstr);
    //执行插入操作
    if (SQLITE_OK != (ret = sqlite3_exec(my_db, sqlstr, NULL, NULL, NULL)))
    {
        printf("errcode:[%d]   errstr:[%s]\n", ret, sqlite3_errmsg(my_db));
        msg->code = -1;
        snprintf(msg->txt, sizeof(msg->txt), "errcode:[%d]   errstr:[%s]\n", ret, sqlite3_errmsg(my_db));
        send(sockfd, msg, sizeof(*msg), 0);
        return -1;
    }

    while (fgets(temp, 300, fp))
    {
        if (strncmp(temp, msg->txt, len) == 0 && temp[len] == ' ')
        {
            p = temp + len;
            while (*p == ' ')
                p++;
            strcpy(msg->txt, p);
            send(sockfd, msg, sizeof(*msg), 0);
            return 0;
        }
    }
    puts("1");
    msg->code = -1;
    send(sockfd, msg, sizeof(*msg), 0);
}

客户端:

int quary(int sockfd, msg_t *msg)
{
    char buff[16] = {0};

    printf("请输入你要查的单词:");
    fgets(buff, sizeof(buff), stdin);
    buff[strlen(buff) - 1] = '\0';

    msg->code=4;
    strcpy(msg->txt,buff);
    send(sockfd, msg, sizeof(*msg), 0);

    recv(sockfd,msg,sizeof(*msg),0);
    if(msg->code==-1){
        printf("查找失败!\n");
    }else{
        printf(" %s  %s\n",buff,msg->txt);
    }
}
((2))查询记录
在命令端选择相应功能,程序调取数据库数据,并显示数据库记录的历史用户查询记录

在这里插入图片描述
代码实现思路:客户端发送请求,服务器执行数据库查找操作,并将每一次的记录发送过去,客户端循环接收、打印。
服务器:

int callback(void *arg, int column, char** f_value, char** f_name){
   int connectfd;
	msg_t msg;
	connectfd = *(int *)arg;
    sprintf(msg.txt, "%s : %s : %s",f_value[0], f_value[1], f_value[2]);
	send(connectfd, &msg, sizeof(msg), 0);
    return 0;//该函数必须要有返回值 否则报错 query aborted
}
int history(int sockfd, msg_t *msg, sqlite3 *my_db)
{
   char sqlstr[128], *errmsg;

	//查询历史表
	sprintf(sqlstr, "select * from record ");
	if (sqlite3_exec(my_db, sqlstr, callback, (void *)&sockfd, &errmsg) != SQLITE_OK)
	{
		printf("error : %s\n", errmsg);
		sqlite3_free(errmsg);
	}

	//发送结束标志
	strcpy(msg->txt, "quit");
	send(sockfd, msg, sizeof(*msg), 0);
    return 0;
}

客户端:

int history(int sockfd, msg_t *msg)
{
    memset(msg,sizeof(*msg),0);
    msg->code=5;
    send(sockfd, msg, sizeof(*msg), 0);
    while(1){ 
        if(recv(sockfd,msg,sizeof(*msg),0)==-1) 
        PRIN_ERROR("recv _history error");
        if(strncmp(msg->txt,"quit",5)==0)break;
        printf("%s\n",msg->txt);
    }
    return 0;
}
((3))返回上一级目录
goto 跳转

(3)退出

退出当前进程。exit(0)

总结

此次小试牛刀,颇有挑战,也有许多瑕疵。供各位看官参考指正。基于tcp的在线词典后续我会出个io多路复用的TCP并发服务器在线词典,比较符合实际需求。实现TCP并发  --多进程  多线程  io多路复用 均可,有兴趣的小白可以试试。

需要源码可以联系我。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值