🚀 Redis 精简版(MiniRedis):内存存储 + 命令解析
目标:打造一个可以在命令行下运行的 Redis Mini 实现,支持基本命令:SET、GET、DEL,并支持简单的 TCP 客户端连接。

📁 项目结构
less
复制
编辑
MiniRedis/
├── main.cpp // 启动入口
├── server.cpp/h // 网络服务器代码(监听连接)
├── command.cpp/h // 命令解析与执行
├── datastore.cpp/h // 内存数据库
├── utils.h // 辅助函数
✅ 支持的基础命令
命令 功能
SET key value 设置 key 的值
GET key 获取 key 的值
DEL key 删除 key
EXIT 断开连接
🧠 第一步:数据存储模块(datastore.h/.cpp)
cpp
复制
编辑
// datastore.h

pragma once

include <unordered_map>

include <string>

include <mutex>

class DataStore {
public:

std::string get(const std::string& key);
void set(const std::string& key, const std::string& value);
bool del(const std::string& key);

private:

std::unordered_map<std::string, std::string> store;
std::mutex mtx; // 支持并发访问

};
cpp
复制
编辑
// datastore.cpp

include "datastore.h"

std::string DataStore::get(const std::string& key) {

std::lock_guard<std::mutex> lock(mtx);
return store.count(key) ? store[key] : "nil";

}

void DataStore::set(const std::string& key, const std::string& value) {

std::lock_guard<std::mutex> lock(mtx);
store[key] = value;

}

bool DataStore::del(const std::string& key) {

std::lock_guard<std::mutex> lock(mtx);
return store.erase(key) > 0;

}
🧠 第二步:命令解析与执行(command.h/.cpp)
cpp
复制
编辑
// command.h

pragma once

include <string>

include "datastore.h"

std::string executeCommand(const std::string& input, DataStore& store);
cpp
复制
编辑
// command.cpp

include "command.h"

include <sstream>

include <vector>

std::vector<std::string> split(const std::string& str) {

std::istringstream iss(str);
std::string token;
std::vector<std::string> tokens;
while (iss >> token) tokens.push_back(token);
return tokens;

}

std::string executeCommand(const std::string& input, DataStore& store) {

auto tokens = split(input);
if (tokens.empty()) return "Invalid command\n";

const std::string& cmd = tokens[0];
if (cmd == "SET" && tokens.size() == 3) {
    store.set(tokens[1], tokens[2]);
    return "OK\n";
}
if (cmd == "GET" && tokens.size() == 2) {
    return store.get(tokens[1]) + "\n";
}
if (cmd == "DEL" && tokens.size() == 2) {
    return store.del(tokens[1]) ? "Deleted\n" : "Key not found\n";
}
if (cmd == "EXIT") {
    return "BYE\n";
}

return "Unknown or invalid command\n";

}
🧠 第三步:网络服务模块(server.cpp)
使用 socket + select 处理多个客户端的连接

cpp
复制
编辑
// main.cpp

include "datastore.h"

include "command.h"

include <iostream>

include <thread>

include <netinet/in.h>

include <unistd.h>

void handleClient(int clientSocket, DataStore& store) {

char buffer[1024] = {0};
while (true) {
    int bytes = read(clientSocket, buffer, sizeof(buffer) - 1);
    if (bytes <= 0) break;

    buffer[bytes] = '\0';
    std::string response = executeCommand(buffer, store);

    if (response == "BYE\n") {
        write(clientSocket, response.c_str(), response.length());
        break;
    }

    write(clientSocket, response.c_str(), response.length());
}
close(clientSocket);

}

int main() {

int server_fd, new_socket;
sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);

server_fd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(6379);

bind(server_fd, (struct sockaddr*)&address, sizeof(address));
listen(server_fd, 3);

std::cout << "MiniRedis started on port 6379...\n";
DataStore store;

while (true) {
    new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
    std::thread(handleClient, new_socket, std::ref(store)).detach();
}

return 0;

}
✅ 示例运行效果
shell
复制
编辑
$ telnet localhost 6379
Trying 127.0.0.1...
Connected to localhost.
SET name ChatGPT
OK
GET name
ChatGPT
DEL name
Deleted
GET name
nil
EXIT
BYE
🚀 可扩展方向
你可以逐步扩展:

扩展内容 实现建议
支持过期时间 TTL 增加一个 map 存储过期时间 + 定时清理
实现 LRU 缓存 使用 std::list + map 双向链表实现
支持事务 MULTI 维护一个命令队列,等待 EXEC 执行
支持持久化(RDB) 将数据定期写入磁盘
客户端 CLI 工具 自定义命令行客户端


唠叨的甘蔗
4 声望1 粉丝