基于TCP的在线词典(包含全部源码)


一、功能说明与演示

1.本词典的主要功能有

注册:
		用户注册的时候,会提示注册信息,成功或失败。如果用户已经存在了,则会提示”注册失败,用户已存在“
登录:
		用户输入用户名和密码进行登录,输入错误则会提示用户重新输入。
查询单词:
		查询单词,在终端显示单词的解释。
查询历史记录:
		当用户选择查看历史记录的时候,会在终端显示当前登录的用户的历史查询信息,在什么时间查询了什么单词。

2.功能演示

1.注册
在这里插入图片描述
2.登录
在这里插入图片描述
登录成功后,会跳转到查询页面
在这里插入图片描述
3.查询
在这里插入图片描述
4.历史记录
在这里插入图片描述

二、流程图

在这里插入图片描述

三、代码实现

1.服务器端

server.h

#ifndef __SERVER_H__
#define __SERVER_H__
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <pthread.h>
#include <signal.h>
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define SERVER_IP "192.168.250.100"
#define SERVER_PORT "8889"

// #define USRNAME "./usrname.txt"
// #define PASSWROD "./password.txt"
#define DATABASE "info.db"
#define FILE_ "./dict.txt"

#define ERRLOG(msg)                                         \
    do {                                                    \
        printf("%s:%s:%d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        exit(-1);                                           \
    } while (0)

typedef struct _MSG {
    char code; //操作码:登录,注册,查询,退出
    char name[32]; //此处是用户名
    char word[32];
    char txt[256]; //登录和注册的时候,此处是密码。查询单词的时候,此处是查询到的单词的解释。如果用户不存在,此处可以是错误信息
} _MSG;

#endif

server.c

#include "server.h"

int max_fd = 0;
int acceptfd = 0;
int loop = 0;
char send_buf[128] = { 0 };
//创建要监视的文件描述集合
fd_set readfds; //母本
fd_set readfds_temp; //给select擦除用的

//数据库初始化的函数
sqlite3* init_process()
{
    int ret = 0;
    sqlite3* save_word_db = NULL;
    char* errmsg = NULL;
    char sqlbuff[256] = { 0 };
    //打开数据库文件
    if (SQLITE_OK != (ret = sqlite3_open(DATABASE, &save_word_db))) {
        printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(save_word_db));
        exit(-1);
    }
    printf("数据库文件 [%s] 打开成功..\n", DATABASE);
    //尝试建表
    //组装sql语句 代码中写的sql语句可以不加分号
    // IF NOT EXISTS 表示如果表不存在则新建 存在就直接使用
    sprintf(sqlbuff, "CREATE TABLE IF NOT EXISTS usrinfo(usrname CHAR PRIMARY KEY, password TEXT)");
    //执行sql语句
    if (SQLITE_OK != (ret = sqlite3_exec(save_word_db, sqlbuff, NULL, NULL, &errmsg))) {
        printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, errmsg);
        exit(-1);
    }

    sprintf(sqlbuff, "CREATE TABLE IF NOT EXISTS English(word CHAR PRIMARY KEY, explanation TEXT)");
    //执行sql语句
    if (SQLITE_OK != (ret = sqlite3_exec(save_word_db, sqlbuff, NULL, NULL, &errmsg))) {
        printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, errmsg);
        exit(-1);
    }

    printf("数据表创建成功..\n");
    //释放errmsg指向的内存空间
    sqlite3_free(errmsg);
    return save_word_db;
}

void word_obtain_and_insert(FILE* dict, sqlite3* save_word_db)
{
    // 1.每行内容不超过300个
    char tmp_buf[300] = { 0 };
    char word[32] = { 0 };

    char recv_char;
    int i = 0;
    int j = 0;
    int worded = 0;
    int over = 0;
    int space = 0;

    //使用sqlite3_prepare可以将插入的时间进一步压缩,原本插入2万条记录需要15秒,现在只需1秒即可完成!!!!
    sqlite3_exec(save_word_db, "begin;", 0, 0, 0);
    sqlite3_stmt* stmt;
    const char* sql = "INSERT INTO English values(?,?)";
    sqlite3_prepare(save_word_db, sql, strlen(sql), &stmt, 0);

    while (!(feof(dict) || ferror(dict))) {

        recv_char = getc(dict);
        if (recv_char == EOF) {
            break;
        }
        //最后一次由于读到EOF跳出循环了,不会打印,但是存储是正常的
        if (recv_char == '\n') {

            //将单词和解释插入save.db数据库中的English表中
            sqlite3_reset(stmt);
            sqlite3_bind_text(stmt, 1, word, strlen(word), NULL);
            sqlite3_bind_text(stmt, 2, tmp_buf, strlen(tmp_buf), NULL);
            sqlite3_step(stmt);

            //清零,便于下一行的单词和解释的获取
            memset(word, 0, sizeof(word));
            memset(tmp_buf, 0, sizeof(tmp_buf));
            //每次到换行符这里,光标其实已经移动到下一行的开头了,因此,把这些变量都归零一下
            i = 0;
            j = 0;
            worded = 0;
            over = 0;
            continue;
        }

        //获取单词
        if (worded == 0) {
            if (' ' == recv_char) {
                //如果是一个词组(两个单词中间会以空格隔开),就往后再判断一位,如果还是空格,就不continue了,直接跳出
                if (' ' == (recv_char = getc(dict))) {
                    fseek(dict, -1, SEEK_CUR);
                    goto SKIP;
                }
                fseek(dict, -2, SEEK_CUR);
                recv_char = getc(dict);
            }
            if (recv_char == '\'') { //注意,此处也要加!!!单词中也可能有o'clock 这种形式的,被坑了一下.........
                recv_char = '.';
            }
            word[i] = recv_char;
            i++;
            continue;
        }
    SKIP:
        worded = 1;

        //获取空格(个数)
        if (' ' == recv_char && over == 0) {
            space++;
            continue;
        }
        over = 1;
        //获取解释
        if ('\n' != recv_char) {
            if (recv_char == '\'') {
                recv_char = '.';
            }
            tmp_buf[j] = recv_char;
            j++;
        }
    }
    sqlite3_finalize(stmt);
    sqlite3_exec(save_word_db, "commit;", 0, 0, 0);
}

int main(int argc, const char* argv[])
{
    // 打开文件,读取每行开头的单词,然后遇到空格就停止,后面再遇到第一个不是空格的字符,就开始保存,直到这一行的结尾
    FILE* dict;
    if (!(dict = fopen(FILE_, "r"))) {
        perror("fopen error");
        exit(-1);
    }
    //创建数据库,创建表
    sqlite3* usrinfo_db = init_process();
    //向表中插入单词
    word_obtain_and_insert(dict, usrinfo_db);
    printf("单词信息插入成功..\n");

    //创建套接字 流式套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd) {
        ERRLOG("socket error");
    }

    //填充网络信息结构体
    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP);
    serveraddr.sin_port = htons(atoi(SERVER_PORT));
    socklen_t serveraddr_len = sizeof(serveraddr);

    //设置允许端口复用,注意要加在 填充网络信息结构体 和  bind  函数之间
    int value = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));

    //绑定
    if (-1 == bind(sockfd, (struct sockaddr*)&serveraddr, serveraddr_len)) {
        ERRLOG("bind error");
    }

    //将套接字设置成被动监听状态
    if (-1 == listen(sockfd, 5)) {
        ERRLOG("listen error");
    }

    //清空集合
    FD_ZERO(&readfds);
    FD_ZERO(&readfds_temp);
    //将sockfd添加到集合中
    FD_SET(sockfd, &readfds);
    //更新最大文件描述符
    max_fd = max_fd > sockfd ? max_fd : sockfd;

    int ret = 0;
    int i = 0;
    int nbytes = 0;
    // char buff[128] = { 0 };
    _MSG msg;
    memset(&msg, 0, sizeof(msg));

    //创建数据库和用户名&密码表
    // sqlite3* usrinfo_db = init_process();
    char sqlbuff[500] = { 0 };
    char* errmsg = NULL;
    char** result = NULL;
    int rows = 0;
    int columns = 0;
    time_t ts;
    struct tm* tm;
    while (1) {
        readfds_temp = readfds;

        if (-1 == (ret = select(max_fd + 1, &readfds_temp, NULL, NULL, NULL))) {
            ERRLOG("select error");
        }
        //遍历集合 看哪个文件描述符就绪了
        for (i = 3; i < max_fd + 1 && ret != 0; i++) {
            if (FD_ISSET(i, &readfds_temp)) {
                if (sockfd == i) {
                    //说明有新客户端连接了
                    if (-1 == (acceptfd = accept(sockfd, NULL, NULL))) {
                        ERRLOG("accept error");
                    }
                    printf("客户端[%d]连接..\n", acceptfd);
                    //将新客户端的acceptfd加入到集合
                    FD_SET(acceptfd, &readfds);
                    //更新最大文件描述符
                    max_fd = max_fd > acceptfd ? max_fd : acceptfd;

                } else {
                    if (-1 == (nbytes = recv(i, &msg, sizeof(msg), 0))) {
                        printf("recv error");
                    } else if (0 == nbytes) {
                        printf("客户端[%d]断开连接..\n", i);

                        FD_CLR(i, &readfds);
                        close(i);
                        continue;
                    }
                    // printf("~~~%s\n", msg.txt);
                    if (!strncmp(msg.txt, "quit", 4)) {
                        printf("客户端[%d]退出了..\n", i);

                        FD_CLR(i, &readfds);
                        close(i);
                        continue;
                    }
                    // printf("~~~%s\n", msg.name);
                    // printf("~~~%s\n", msg.txt);
                    switch (msg.code) {
                    case 'L':
                        //如果读取正常,用户也没退出,那么就开始判断用户传过来的数据,判断用户是否存在
                        //组装SQL语句
                        sprintf(sqlbuff, "SELECT * FROM usrinfo WHERE usrname='%s' AND password='%s'", msg.name,msg.txt);
                        // printf("-----sql = %s", sqlbuff);
                        //执行sql语句
                        if (SQLITE_OK != (ret = sqlite3_get_table(usrinfo_db, sqlbuff, &result, &rows, &columns, NULL))) {
                            printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                        }
                        //记得释放结果集
                        sqlite3_free_table(result); //!!!

                        if (rows == 0) {
                            strncpy(msg.txt, "L_F", 3);
                        } else if (rows == 1) {
                            //有用户登陆成功,就为用户创建一个历史记录表
                            sprintf(sqlbuff, "CREATE TABLE IF NOT EXISTS %s_history(who CHAR,time CHAR,history TEXT)", msg.name);
                            printf("222zjh222 %s\n", sqlbuff); //
                            //执行sql语句
                            if (SQLITE_OK != (ret = sqlite3_exec(usrinfo_db, sqlbuff, NULL, NULL, &errmsg))) {
                                printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, errmsg);
                                // exit(-1);
                            }

                            strncpy(msg.txt, "L_S", 3);
                        }
                        //发送信息到客户端
                        if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                            ERRLOG("send error");
                        }
                        break;
                    case 'R':
                        //如果读取正常,用户也没退出,那么就开始判断用户传过来的数据,判断用户是否存在
                        //组装SQL语句
                        sprintf(sqlbuff, "INSERT INTO usrinfo VALUES('%s','%s')", msg.name, msg.txt);
                        // printf("-----sql = %s", sqlbuff);
                        //执行sql语句
                        if (SQLITE_OK != (ret = sqlite3_exec(usrinfo_db, sqlbuff, NULL, NULL, NULL))) {
                            strncpy(msg.txt, "R_F", 3);
                            printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                            // exit(-1);
                        } else {
                            strncpy(msg.txt, "R_S", 3);
                        }
                        //发送信息到客户端
                        if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                            ERRLOG("send error");
                        }
                        break;
                    case 'S':
                        //组装SQL语句
                        sprintf(sqlbuff, "SELECT word FROM English WHERE word='%s'", msg.word);
                        if (SQLITE_OK != (ret = sqlite3_exec(usrinfo_db, sqlbuff, NULL, NULL, NULL))) {
                            strncpy(msg.txt, "S_F", 3);
                            printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                            // exit(-1);
                        } else {
                            // //应该先提取用户输入的单词,再把这个位置填为查询成功
                            sprintf(sqlbuff, "SELECT explanation FROM English WHERE word='%s'", msg.word);
                            //执行sql语句
                            if (SQLITE_OK != (ret = sqlite3_get_table(usrinfo_db, sqlbuff, &result, &rows, &columns, NULL))) {
                                printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                            } else {

                                //如果执行到这儿 说明查询成功了 处理查询结果
                                int m = 0;
                                int n = 0;
                                for (m = 0; m < rows + 1; m++) {
                                    for (n = 0; n < columns; n++) {
                                        // printf("%10s", result[i * columns + j]);
                                        strcpy(msg.txt, result[m * columns + n]);
                                    }
                                    printf("\n");
                                }

                                //每次查询成功,还要将本次用户查询的信息插入到:用户名_history 表中
                                //组装SQL语句
                                //获取系统时间
                                if ((ts = time(NULL)) == (time_t)-1)
                                    ERRLOG("get time second error");
                                if ((tm = localtime(&ts)) == NULL)
                                    ERRLOG("change time error");
                                char time[128] = { 0 };
                                sprintf(time, " %d-%02d-%02d %02d:%02d:%02d ", tm->tm_year + 1900,
                                    tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

                                sprintf(sqlbuff, "INSERT INTO %s_history VALUES('%s','%s','%s')", msg.name, msg.name, time, msg.word);
                                // printf("111zjh111sql = %s", sqlbuff); //
                                //执行sql语句
                                if (SQLITE_OK != (ret = sqlite3_exec(usrinfo_db, sqlbuff, NULL, NULL, NULL))) {
                                    printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                                }

                                strncpy(msg.word, "S_S", 3);
                            }
                            //记得释放结果集
                            sqlite3_free_table(result); //!!!
                        }
                        //发送信息到客户端
                        if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                            ERRLOG("send error");
                        }

                        break;
                    case 'H':
                        //应该先提取用户输入的单词,再把这个位置填为查询成功
                        sprintf(sqlbuff, "SELECT * FROM %s_history", msg.name);
                        // printf("+++++%s\n", sqlbuff);
                        //执行sql语句
                        if (SQLITE_OK != (ret = sqlite3_get_table(usrinfo_db, sqlbuff, &result, &rows, &columns, NULL))) {
                            strncpy(msg.word, "H_F", 3);
                            printf("%s:%d -- errcode[%d] errstr[%s]\n", __FILE__, __LINE__, ret, sqlite3_errmsg(usrinfo_db));
                            //发送信息到客户端
                            if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                                ERRLOG("send error");
                            }
                        } else {
                            strncpy(msg.word, "H_S", 3);
                            //如果执行到这儿 说明查询成功了 处理查询结果
                            int m = 0;
                            int n = 0;
                            for (m = 0; m < rows + 1; m++) {
                                for (n = 0; n < columns; n++) {
                                    printf("%10s", result[m * columns + n]);
                                    memset(msg.txt, 0, sizeof(msg.txt));
                                    strcpy(msg.txt, result[m * columns + n]);
                                    //发送信息到客户端
                                    if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                                        ERRLOG("send error");
                                    }
                                }
                                printf("\n");
                            }
                            strncpy(msg.word, "over", 4);
                            //发送信息到客户端
                            if (-1 == send(i, &msg, sizeof(_MSG), 0)) {
                                ERRLOG("send error");
                            }
                        }
                        //记得释放结果集
                        sqlite3_free_table(result); //!!!

                        break;
                    }
                }
            }
        }
    }

    return 0;
}

2.客户端

client.h

#ifndef __CLIENT_H__
#define __CLIENT_H__
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define LOG_IN 1
#define REGISTER 2
#define QUIT 3
#define QUERY 1
#define HISTORY 2

// #define SERVER_IP "112.74.89.58"
// #define SERVER_PORT "39045"

#define SERVER_IP "192.168.250.100"
#define SERVER_PORT "8889"

#define ERRLOG(msg)                                         \
    do {                                                    \
        printf("%s:%s:%d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        exit(-1);                                           \
    } while (0)

typedef struct _MSG {
    char code; //操作码:登录,注册,查询,退出
    char name[32]; //此处是用户名
    char word[32];
    char txt[256]; //登录和注册的时候,此处是密码。查询单词的时候,此处是查询到的单词的解释。如果用户不存在,此处可以是错误信息
} _MSG;

#endif

client.c

#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define LOG_IN 1
#define REGISTER 2
#define QUIT 3
#define QUERY 1
#define HISTORY 2

// #define SERVER_IP "112.74.89.58"
// #define SERVER_PORT "39045"

#define SERVER_IP "192.168.250.100"
#define SERVER_PORT "8889"

#define ERRLOG(msg)                                         \
    do {                                                    \
        printf("%s:%s:%d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        exit(-1);                                           \
    } while (0)

typedef struct _MSG {
    char code; //操作码:登录,注册,查询,退出
    char name[32]; //此处是用户名
    char word[32];
    char txt[256]; //登录和注册的时候,此处是密码。查询单词的时候,此处是查询到的单词的解释。如果用户不存在,此处可以是错误信息
} _MSG;

int nbytes = 0;
int first_input_choice(_MSG* msg, int sockfd)
{
    int choice = 0;

// 1.提示信息
BEGIN:
    system("clear");
    printf("--------------------------\n");
    printf("| 欢迎使用在线词典,请选择 |\n");
    printf("|  1.登录 2.注册 3.退出   |\n");
    printf("--------------------------\n");
    scanf("%d", &choice);
    getchar();
    if (choice != 1 && choice != 2 && choice != 3) {
        goto BEGIN;
    }
    // 2.读取用户输入的选择:登录,注册,还是退出,然后继续相应的操作
    switch (choice) {
        //登录,输入用户名和密码
    case LOG_IN:
        printf("|  登录   |\n");
        memset(msg, 0, sizeof(_MSG));
        printf("请输入用户名:  \n");
        scanf("%s", msg->name);
        getchar();
        printf("请输入密码:  \n");
        scanf("%s", msg->txt);
        getchar();
        msg->code = 'L'; //设置操作码为登录

        //发送信息到服务器
        if (-1 == send(sockfd, msg, sizeof(_MSG), 0)) {
            ERRLOG("send error");
        }
        if (-1 == (nbytes = recv(sockfd, msg, sizeof(_MSG), 0))) {
            ERRLOG("recv ersockfdror");
        }

        break;
        //注册,输入用户名和密码
    case REGISTER:
        printf("|  注册   |\n");
        memset(msg, 0, sizeof(_MSG));
        printf("请输入用户名:  \n");
        scanf("%s", msg->name);
        printf("请输入密码:  \n");
        scanf("%s", msg->txt);
        msg->code = 'R'; //设置操作码为注册

        //发送信息到服务器
        if (-1 == send(sockfd, msg, sizeof(_MSG), 0)) {
            ERRLOG("send error");
        }
        //接收服务器发来的消息
        if (-1 == (nbytes = recv(sockfd, msg, sizeof(_MSG), 0))) {
            ERRLOG("recv ersockfdror");
        }

        break;
    case QUIT:
        strcpy(msg->txt, "quit");
        printf("~~%s\n", msg->txt);
        if (-1 == send(sockfd, msg, sizeof(_MSG), 0)) {
            ERRLOG("send error");
        }
        printf("|  欢迎下次使用本系统.   |\n");
        exit(-1);
        break;
    }
    return choice;
}

void query_choice(_MSG* msg, int sockfd)
{
    int loop = 0;
    int once = 0;
    int first = 3;
    int choice = 0;
    // 1.提示信息
BEGIN:
    system("clear");
    printf("用户:%s>>>\n", msg->name);
    printf("----------------------------\n");
    printf("|      在线词典,请选择      |\n");
    printf("|  1.查询 2.历史记录 3.退出 |\n");
    printf("----------------------------\n");
    scanf("%d", &choice);
    getchar();
    if (choice != 1 && choice != 2 && choice != 3) {
        goto BEGIN;
    }
    switch (choice) {
        //查询,输入单词
    case QUERY:
        printf("请输入要查询的单词: \n");
        memset(msg->word, 0, sizeof(msg->word));
        scanf("%s", msg->word);
        msg->code = 'S'; //设置操作码为查询(select)
        //发送信息到服务器
        if (-1 == send(sockfd, msg, sizeof(_MSG), 0)) {
            ERRLOG("send error");
        }
        //接收服务器发来的消息
        if (-1 == (nbytes = recv(sockfd, msg, sizeof(_MSG), 0))) {
            ERRLOG("recv ersockfdror");
        }
        printf(">>>  %s\n", msg->txt);
        getchar();
        printf("请按任意键继续..\n");
        getchar();
        break;
        //查看历史记录
    case HISTORY:
        msg->code = 'H'; //设置操作码为查询历史记录(history)
        memset(msg->word, 0, sizeof(msg->word));
        memset(msg->txt, 0, sizeof(msg->txt));
        //发送信息到服务器
        if (-1 == send(sockfd, msg, sizeof(_MSG), 0)) {
            ERRLOG("send error");
        }
        //接收服务器发来的消息
        while (0 != strncmp(msg->word, "over", 4)) {
            printf(" %s ", msg->txt);
            //第一行的内容,表头信息,要隔开,不要距离太近
            if (first != 0 && once == 1) {
                printf("\t   ");
                first--;
            }
            if (once == 0) {
                once = 1;
                printf("\n");
            }

            if (loop == 3) {
                printf("\n");
                loop = 0;
            }
            loop++;

            if (-1 == (nbytes = recv(sockfd, msg, sizeof(_MSG), 0))) {
                ERRLOG("recv ersockfdror");
            }
        }
        printf("\n");
        printf("请按任意键继续..\n");
        getchar();
        break;
    case QUIT:
        strcpy(msg->txt, "quit");
        break;
    }
}

int main(int argc, char const* argv[])
{
    //创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sockfd) {
        ERRLOG("socket error");
    }
    //填充服务器网络信息结构体
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(SERVER_PORT));
    serveraddr.sin_addr.s_addr = inet_addr(SERVER_IP);
    socklen_t serveraddr_len = sizeof(serveraddr);
    //与服务器建立连接
    if (-1 == connect(sockfd, (struct sockaddr*)&serveraddr, serveraddr_len)) {
        ERRLOG("connect error");
    }

    _MSG msg;

    while (1) {
        memset(&msg, 0, sizeof(msg));
        first_input_choice(&msg, sockfd);
        //判断登录是否成功
        if (0 == strncmp(msg.txt, "L_S", 3)) {
            printf("登陆成功..\n");
            while (1) {
                query_choice(&msg, sockfd);
                if (0 == strncmp(msg.txt, "quit", 4))
                    break;
            }
        } else if (0 == strncmp(msg.txt, "L_F", 3)) {
            printf("登陆失败,请检查用户名和密码后重新输入..\n");
            printf("请按任意键继续..\n");
            getchar();
        }
        //判断注册是否成功
        if (0 == strncmp(msg.txt, "R_S", 3)) {
            printf("注册成功..\n");
            printf("请按任意键继续..\n");
            getchar();
            getchar();
        } else if (0 == strncmp(msg.txt, "R_F", 3)) {
            printf("注册失败,用户已存在..\n");
            printf("请按任意键继续..\n");
            getchar();
            getchar();
        }
    }

    return 0;
}

总结

对于一些步骤和需要注意的点,已经在代码中通过注释的形式说明(在这里偷个懒,希望各位看官见谅T_T),如果有不合适或者错误的地方,希望大家批评指正,我会虚心改正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值