为什么respreply redisconnection::receiveresp()只执行客户端列表的几个字节?

vxbzzdmp  于 2021-06-07  发布在  Redis
关注(0)|答案(0)|浏览(286)

在执行客户机列表时,socket的read()只返回几个字节,正常情况下应该返回相关信息。
我试图根据read()返回0来判断结束,但是当我执行客户机列表时,第一个只读取了几个字节
“客户端列表”
正确结果正确答案
我的错误答案错误答案
连接.h


# ifndef CONNECTION_H

# define CONNECTION_H

# include <sys/socket.h>

# include <arpa/inet.h>

# include <unistd.h>

# include <iostream>

# include <string>

# include <vector>

# include "../utils/resp_utils.h"

# define BUFFER_SIZE 1024

using std::cout;
using std::endl;
using std::string;

typedef struct sockaddr_in SocketAddr;

class RedisConnection {
public:
    RedisConnection(string _host, unsigned int _port = 6379) : host(_host), port(_port) {
    }

    ~RedisConnection() {

    }

    bool Connect();

    bool Close();

    RESPReply SendCommand(const std::string& command);
    RESPReply ReceiveResp();

private:
    bool Init();

private:
    string host;
    unsigned int port;
    // redis descriptor 
    int sock{0};
    SocketAddr server_addr;
};

# endif

连接.cpp


# include "connection.h"

bool RedisConnection::Connect() {
    if (!Init()) {
        return false;
    }

    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        cout << "connect failed" << endl;
        return false;
    }
    return true;
}

bool RedisConnection::Init() {
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        cout << "socket create error" << endl;
        return false;
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);

    if (inet_pton(AF_INET, host.c_str(), &server_addr.sin_addr) <= 0) {
        cout << "invalid address / address not supported" << endl;
        return false;
    }

    return true;
}

bool RedisConnection::Close() {
    int res = close(sock);
    if (res == 0) {
        return true;
    }
    cout << "close failed[" << errno << "] " << endl;
    return false;
}

RESPReply RedisConnection::SendCommand(const std::string& command) {
    RESPReply reply;
    if (send(sock, (char *)command.c_str(), command.size(), 0) < 0) {
        reply.errorCode = -1;
        reply.innerError = enumSocketSendMsgFailed;
        cout << "send failed[" << errno << "] " << endl;
        return reply;
    }

    return ReceiveResp();
}

RESPReply RedisConnection::ReceiveResp() {
    string reply(BUFFER_SIZE, 0);
    int start = 0;
    while (1) {
        int readBytes = read(sock, &reply[start], BUFFER_SIZE - 1);
        cout << "read bytes:" << readBytes << endl;
        cout << "reply:" << reply << endl;
        if (readBytes < 0) {
            cout << "failed read data from socket" << endl;
            break;
        } else if (readBytes == 0) {
            cout << "read done data from socket" << endl;
            break;
        } else {
            if (readBytes >= BUFFER_SIZE - 1) {
                string temp = reply;
                reply.resize(temp.size() * 2);
                reply = temp;
            } else {
                start += readBytes;
                break;
            }
        }
    }

    return RESPUtils::ConvertToRESPReply(reply);
    // cout << RESPUtils::ConvertToSimpleString(reply) << endl;
}

int main(void) 
{
    RedisConnection connection("10.10.243.233");
    if (connection.Connect()) {
        cout << "Connected to Redis success" << endl;
    }

    RESPReply reply = connection.SendCommand("auth aaaaaa\r\n");
    // cout << reply.type << " " << reply.str << endl;
    reply = connection.SendCommand("ping\r\n");

    // cout << reply.type << " " << reply.str << endl;

    reply = connection.SendCommand("ping1\r\n");
    // cout << reply.type << " " << reply.str << endl;

    reply = connection.SendCommand("DBSIZE\r\n");
    // cout << reply.type << " " << reply.integerResp << endl;

    reply = connection.SendCommand("client list\r\n");
    // cout << reply.type << " " << reply.integerResp << endl;

    return 0;
}

责任人


# ifndef RESP_UTILS_H

# define RESP_UTILS_H

# include <map>

# include <functional>

# include <algorithm>

# include "utils.h"

# define int64 int64_t

enum RESPType {
    enumRESPSimpleString = 0,           // simple string "+"
    enumRESPErrors = 1,                 // error         "-"
    enumRESPIntegers = 2,               // int           ":"
    enumRESPBulkStrings = 3,            // bulk strings  "$"
    enumRESPArrays = 4,                 // array         "*"
};

enum EnumInnerError {
    enumArgumentInvalid = 1,
    enumRedisTypeInvalid = 2,
    enumSocketSendMsgFailed = 3,
};

enum EnumOuterError {

};

struct RESPReply {
    std::string str;
    std::vector<std::string> bulkStrs;
    int64 integerResp;

    // 返回类型
    RESPType type;

    EnumInnerError innerError;
    // -1 innerError -2 outerError
    int errorCode;

    RESPReply() {
        Reset();
    }

    RESPReply(const RESPReply& another) {
        str = another.str;
        bulkStrs = another.bulkStrs;
        type = another.type;
        innerError = another.innerError;
        errorCode = another.errorCode;
    }

    ~RESPReply() {

    }

    void Reset() {
        type = enumRESPSimpleString;
        errorCode = 0;
        str = "";
        integerResp = 0;
        bulkStrs.clear();

    }
};

typedef std::map<RESPType, std::function<RESPReply(const std::string&)> > Convert;

class RESPUtils {
public:
    static RESPReply ConvertToRESPReply(const std::string& respString) {
        RESPReply reply;
        if (respString.size() == 0) {
            reply.errorCode = -1;
            reply.innerError = enumArgumentInvalid;
            return reply;
        }

        RESPType type;
        if (!IsValidRedisType(respString[0], type)) {
            reply.errorCode = -1;
            reply.innerError = enumRedisTypeInvalid;
            return reply;
        }

        return RESPUtils::converter[type](respString);
    }

    static bool IsValidRedisType(const char& type, RESPType& resType) {
        switch (type) {
            case '+':
                resType = enumRESPSimpleString;
                break;
            case '-':
                resType = enumRESPErrors;
                break;
            case '*':
                resType = enumRESPArrays;
                break;
            case ':':
                resType = enumRESPIntegers;
                break;
            case '$':
                resType = enumRESPBulkStrings;
                break;
            default:
                return false;
        }
        return true;
    }

    static RESPReply ConvertToError(const std::string& respError);

    static RESPReply ConvertToSimpleString(const std::string& respSimpleString);

    static RESPReply ConvertToInteger(const std::string& respInteger);

    static RESPReply ConvertToBulkStrings(const std::string& respBulkStrings);

private:

    static Convert  converter;
};

RESPReply RESPUtils::ConvertToError(const std::string& respError) {
    RESPReply reply;
    reply.errorCode = 0;
    reply.type = enumRESPErrors;
    size_t crlf = respError.find("\r\n");
    if (crlf != std::string::npos) {
        reply.str = respError.substr(1, crlf - 1);
    }
    return reply;
}

RESPReply RESPUtils::ConvertToSimpleString(const std::string& respSimpleString) {
    RESPReply reply;
    reply.errorCode = 0;
    reply.type = enumRESPSimpleString;
    size_t crlf = respSimpleString.find("\r\n");
    if (crlf != std::string::npos) {
        reply.str = respSimpleString.substr(1, crlf - 1);
    }

    return reply;
}

RESPReply RESPUtils::ConvertToInteger(const std::string& respInteger) {
    RESPReply reply;
    reply.errorCode = 0;
    reply.type = enumRESPSimpleString;
    size_t crlf = respInteger.find("\r\n");
    if (crlf != std::string::npos) {
        reply.integerResp = stol(respInteger.substr(1, crlf - 1));
    }

    return reply;
}

RESPReply RESPUtils::ConvertToBulkStrings(const std::string& respBulkStrings) {
    std::cout << respBulkStrings << std::endl;
    RESPReply reply;
    reply.errorCode = 0;
    reply.type = enumRESPBulkStrings;
    reply.bulkStrs = MyUtils::SplitString(respBulkStrings.substr(1), "\r\n");

    for (const auto& bulkStr : reply.bulkStrs) {
        std::cout << bulkStr << std::endl;
    }
    return reply;
}

Convert RESPUtils::converter = {
    {enumRESPSimpleString, &ConvertToSimpleString},
    {enumRESPErrors, &ConvertToError},
    {enumRESPIntegers, &ConvertToInteger},
    {enumRESPBulkStrings, &ConvertToBulkStrings},
};

# endif

执行结果

Connected to Redis success
read bytes:5
reply:+OK

read bytes:7
reply:+PONG

read bytes:30
reply:-ERR unknown command 'ping1'

read bytes:8
reply::11471

read bytes:8
reply:$22656

$22656

22656

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题