在执行客户机列表时,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
暂无答案!
目前还没有任何答案,快来回答吧!