c++ redis客户端, 带详情输入输出

文章目录

    • 使用方法
    • 输入
    • 输出解释
    • 代码
    • 输出

使用方法

g++ main.cpp
./a.out -h 127.0.0.1 -p 6379

输入

一行内输入 redis 命令
keys*
set name
get name
等等 redis命令

输出解释

输入redis: redis收到的redis协议的数据
human输入: 你输入的原始字符
redis输出: redis返回的基于 redis协议的数据
human输出: 稍微处理过的 redis放回的数据

代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

string ip = "127.0.0.1";
int p = 6379;

class TcpCli {
public:
    string ip;
    int port;
    int fd;

    explicit TcpCli(const string& ip = "127.0.0.1", int port = 80) {
        this->ip = ip;
        this->port = port;
        fd = -1;
    }

    ~TcpCli() {
        if (fd != -1) {
            close(fd);
        }
    }

     bool connect() {
        // 电话号码
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if (fd == -1) {
            return false;
        }
        // 拨号
        sockaddr_in saddr{};
        saddr.sin_family = AF_INET;
        saddr.sin_port = htons(port);
        saddr.sin_addr.s_addr = inet_addr(ip.c_str());
        int ret = ::connect(fd, (sockaddr *) &saddr, sizeof(saddr));
        if (ret == -1) {
            return false;
        }
        return true;
    }

    int send(const string& data) {
        return ::send(fd, data.c_str(), data.size(), 0);
    }

    int recv(string& data) {
        char buf[1024];
        int ret = ::recv(fd, buf, sizeof(buf), 0);
        if (ret > 0) {
            data.assign(buf, ret);
        }
        return ret;
    }

};

class RedisRequestProtocol {
public:
    static string makeRequest(const vector<string> &args) {
        string res = "*" + to_string(args.size()) + "\r\n";
        res += "$" + to_string(args[0].size()) + "\r\n";
        res += args[0] + "\r\n";
        for (int i = 1; i < args.size(); i++) {
            res += "$" + to_string(args[i].size()) + "\r\n";
            res += args[i] + "\r\n";
        }
        return res;
    };

public:
    static string set(const string &key, const string &value) {
        return makeRequest({"set", key, value});
    }

    static string get(string key) {
        return makeRequest({"get", key});
    }
};

string beautify(const string& data) {
    string res;
    string res2;
    for (int i = 0; i < data.size(); i++) {
        if (data[i] != '\r' && data[i] != '\n') {
            res += data[i];
            res2 += data[i];
            continue;
        }
        if (data[i] == '\r') {
          res += "\\r\\n";
          i++;
        }
    }
    return res;
}

string deleteSome(const string& data, char ch) {
    string res;
    for (int i = 0; i < data.size(); i++) {
        if (data[i] == ch) {
            int pos = data.find("\r\n", i);
            i = pos + 1;
        } else {
            res += data[i];
        }
    }
    return res;
}

string human(const string& data) {
    if (data.empty()) {
        return data;
    }
    if (data[0] == '-') {
        return data.c_str() + 1;
    }
    string res;
    // 删掉多行字符串标记
    string temp = deleteSome(data, '$');
    // 删去数组标记
    temp = deleteSome(temp, '*');
    return res = temp;
}

void tishi(const string& addr, string op = "输入redis:") {
    cout << op << addr;
}

class RedisCli {
public:
    TcpCli cli;
    string addr;
    RedisRequestProtocol requestProtocol;

    RedisCli(string ip = "127.0.0.1", int port = 6379) : cli(ip, port) {
        addr = ip + ":" + to_string(port);
        if (!cli.connect()) {
            cout << "connect error" << endl;
            exit(-1);
        }
    }

    template<class ...Args>
    void runCommand(const Args... args) {
        string request = requestProtocol.makeRequest({args...});
        tishi(addr + "> ");
        cout << beautify(request) << endl;
        auto ret = cli.send(request);
        if (ret == -1) {
            throw "send error";
        }
        string data;
        ret = cli.recv(data);
        if (ret == -1) {
            throw "recv error";
        }
        tishi(addr + "> ", "redis输出:");
        cout << beautify(data)<< endl;
        tishi(addr + ">\n", "human输出:");
        cout << human(data);
    }
};


void parseArgv(int argc, char** argv) {
    int option;
    while((option=getopt(argc, argv, "h:p:"))) {
        switch(option) {
            case 'h':
                ip = optarg;
                break;
            case 'p':
                p = atoi(optarg);
                break;
            default:
                return;
        }
    }
}

int main(int argc, char** argv) {
    parseArgv(argc, argv);
    RedisCli cli(ip, p);
    string command;
    cout << "*********************为了看的清楚, 我们把返回数据的\\r\\n打出来了, 并分行显示*********************" << endl;
    while (true) {
        tishi(cli.addr + "> ", "human输入:");
        if (!getline(cin, command) || command.empty()) {
            continue;
        }
        if (command == "q" || command == "Q") {
            break;
        }
        stringstream ss(command);
        vector<string> args;
        string arg;
        while(ss >> arg) {
            args.push_back(arg);
        }
        cli.runCommand(args);
    }

}

输出

c++ redis客户端, 带详情输入输出_第1张图片

你可能感兴趣的:(c++,redis,bootstrap)