Redis 中文文档 Redis 中文文档
指南
redis.io (opens new window)
指南
redis.io (opens new window)
  • 关于
    • Redis 开源治理
    • Redis 发布周期
    • Redis 赞助商
  • 入门
  • 数据类型
  • Redis Stack
  • 命令
  • 手册

redis-cpp - lightweight C++ client library for Redis


redis-cpp is a C++17 library for executing Redis commands with support for pipelines and the publish / subscribe pattern. Moreover, you can extend the library with your own stream implementation to communicate with Redis. You can also use it like a RESP serializer (pure core). You need only know a couple of functions to start working with Redis.

  1. ``` sh
  2. // Connect to server
  3. auto stream = rediscpp::make_stream("localhost", "6379");
  4. // Execute command
  5. std::cout << rediscpp::execute(*stream, "ping").as() << std::endl;
  6. ```

And you may dive deeper if you feel the need.

NOTEIf you need a C++11 version you could switch to c++11 branch and use that one.

Version


1.1.0

Features


easy way to access Redis
pipelines
publish / subscribe
pure core in C++ for the RESP
extensible transport
header-only library if it's necessary
minimal dependencies
various levels of usage

License


Distributed under the MIT License

Compiler and OS


This has compiled and tested within gcc 9.3 and clang 10.0 on Ubuntu 20.04.You might try other compiler or OS.

NOTEAll code is a cross-platform.

Dependencies


Boost (at least 1.71 only for using with built-in implementation of transport).

Build and install


Build library


  1. ``` shell
  2. git clone https://github.com/tdv/redis-cpp.git  
  3. cd redis-cpp
  4. mkdir build  
  5. cd build  
  6. cmake ..  
  7. make  
  8. make install  
  9. ```

You can use CMAKE_INSTALL_PREFIX to select the installation directoryMoreover, you can use cmake options to configure the library for header-only or pure core.Instead of cmake options, you can define REDISCPP_HEADER_ONLY and use the library as header-only without any cmake file.

NOTEredis-cpp has two build options

Pure core only
Header-only

Use cmake -D with REDISCPP_HEADER_ONLY or REDISCPP_PURE_CORE. You can enable both options at the same time.You can use your own transport with the 'pure core' option.

If you need to use the header-only library, you can copy the folder redis-cpp from include/redis-cppin your project and define the macro REDISCPP_HEADER_ONLY before including the redis-cpp headers following the example code below:

  1. ``` sh
  2. #define REDISCPP_HEADER_ONLY
  3. #include <redis-cpp/stream.h>
  4. #include <redis-cpp/execute.h>

  5. // Include something else
  6. ```

Build examples


  1. ``` shell
  2. cd examples/{example_project}
  3. mkdir build  
  4. cd build  
  5. cmake ..  
  6. make  
  7. ```

Examples


NOTELook at the redis-docker folder to get all you need to start testing redis-cpp. There are files to build and run a Redis server in Docker.

Ping


Source code DescriptionThe "Ping" example demonstrates how to execute a Redis command.

  1. ``` sh
  2. // STD
  3. #include <cstdlib>
  4. #include <iostream>

  5. #include <redis-cpp/stream.h>
  6. #include <redis-cpp/execute.h>

  7. int main()
  8. {
  9.     try
  10.     {
  11.         auto stream = rediscpp::make_stream("localhost", "6379");
  12.         auto response = rediscpp::execute(*stream, "ping");
  13.         std::cout << response.as<std::string>() << std::endl;
  14.     }
  15.     catch (std::exception const &e)
  16.     {
  17.         std::cerr << "Error: " << e.what() << std::endl;
  18.         return EXIT_FAILURE;
  19.     }
  20.     return EXIT_SUCCESS;
  21. }

  22. ```

Set and Get data


Source code DescriptionThe example demonstrates how to set and get a value.

  1. ``` sh
  2. // STD
  3. #include <cstdlib>
  4. #include <iostream>

  5. #include <redis-cpp/stream.h>
  6. #include <redis-cpp/execute.h>

  7. int main()
  8. {
  9.     try
  10.     {
  11.         auto stream = rediscpp::make_stream("localhost", "6379");

  12.         auto const key = "my_key";

  13.         auto response = rediscpp::execute(*stream, "set",
  14.                 key, "Some value for 'my_key'", "ex", "60");

  15.         std::cout << "Set key '" << key << "': " << response.as<std::string>() << std::endl;

  16.         response = rediscpp::execute(*stream, "get", key);
  17.         std::cout << "Get key '" << key << "': " << response.as<std::string>() << std::endl;
  18.     }
  19.     catch (std::exception const &e)
  20.     {
  21.         std::cerr << "Error: " << e.what() << std::endl;
  22.         return EXIT_FAILURE;
  23.     }
  24.     return EXIT_SUCCESS;
  25. }
  26. ```

Pipeline


Source code DescriptionIt's a more complicated example which demonstrates how to use a pipeline within Redis to achieve better performance.

  1. ``` sh
  2. // STD
  3. #include <cstdlib>
  4. #include <iostream>

  5. #include <redis-cpp/stream.h>
  6. #include <redis-cpp/execute.h>

  7. int main()
  8. {
  9.     try
  10.     {
  11.         auto stream = rediscpp::make_stream("localhost", "6379");

  12.         int const N = 10;
  13.         auto const key_pref = "my_key_";

  14.         // Executing command 'SET' N times without getting any response
  15.         for (int i = 0 ; i < N ; ++i)
  16.         {
  17.             auto const item = std::to_string(i);
  18.             rediscpp::execute_no_flush(*stream,
  19.                 "set", key_pref + item, item , "ex", "60");
  20.         }

  21.         // Flush all
  22.         std::flush(*stream);

  23.         // Getting response for each sent 'SET' request
  24.         for (int i = 0 ; i < N ; ++i)
  25.         {
  26.             rediscpp::value value{*stream};
  27.             std::cout << "Set " << key_pref << i << ": "
  28.                       << value.as<std::string_view>() << std::endl;
  29.         }

  30.         // Executing command 'GET' N times without getting any response
  31.         for (int i = 0 ; i < N ; ++i)
  32.         {
  33.             rediscpp::execute_no_flush(*stream, "get",
  34.                 key_pref + std::to_string(i));
  35.         }

  36.         // Flush all
  37.         std::flush(*stream);

  38.         // Getting response for each sent 'GET' request
  39.         for (int i = 0 ; i < N ; ++i)
  40.         {
  41.             rediscpp::value value{*stream};
  42.             std::cout << "Get " << key_pref << i << ": "
  43.                       << value.as<std::string_view>() << std::endl;
  44.         }
  45.     }
  46.     catch (std::exception const &e)
  47.     {
  48.         std::cerr << "Error: " << e.what() << std::endl;
  49.         return EXIT_FAILURE;
  50.     }
  51.     return EXIT_SUCCESS;
  52. }
  53. ```

Resp


Source code DescriptionThe "Resp" example demonstrates a basic RESP serialization within redis-cpp without communication with Redis server. It's meant to show you how to use RESP serialization with redis-cpp library.

  1. ``` sh
  2. // STD
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <sstream>

  6. #include <redis-cpp/execute.h>

  7. namespace resps = rediscpp::resp::serialization;
  8. namespace respds = rediscpp::resp::deserialization;

  9. auto make_sample_data()
  10. {
  11.     std::ostringstream stream;

  12.     put(stream, resps::array{
  13.             resps::simple_string{"This is a simple string."},
  14.             resps::error_message{"This is an error message."},
  15.             resps::bulk_string{"This is a bulk string."},
  16.             resps::integer{100500},
  17.             resps::array{
  18.                 resps::simple_string("This is a simple string in a nested array."),
  19.                 resps::bulk_string("This is a bulk string in a nested array.")
  20.             }
  21.         });

  22.     return stream.str();
  23. }

  24. void print_value(respds::array::item_type const &value, std::ostream &stream)
  25. {
  26.     std::visit(rediscpp::resp::detail::overloaded{
  27.             [&stream] (respds::simple_string const &val)
  28.             { stream << "Simple string: " << val.get() << std::endl; },
  29.             [&stream] (respds::error_message const &val)
  30.             { stream << "Error message: " << val.get() << std::endl; },
  31.             [&stream] (respds::bulk_string const &val)
  32.             { stream << "Bulk string: " << val.get() << std::endl; },
  33.             [&stream] (respds::integer const &val)
  34.             { stream << "Integer: " << val.get() << std::endl; },
  35.             [&stream] (respds::array const &val)
  36.             {
  37.                 stream << "----- Array -----" << std::endl;
  38.                 for (auto const &i : val.get())
  39.                     print_value(i, stream);
  40.                 stream << "-----------------" << std::endl;
  41.             },
  42.             [&stream] (auto const &)
  43.             { stream << "Unexpected value type." << std::endl; }
  44.         }, value);
  45. }

  46. void print_sample_data(std::istream &istream, std::ostream &ostream)
  47. {
  48.     rediscpp::value value{istream};
  49.     print_value(value.get(), ostream);
  50. }

  51. int main()
  52. {
  53.     try
  54.     {
  55.         auto const data = make_sample_data();
  56.         std::cout << "------------ Serialization ------------" << std::endl;
  57.         std::cout << data << std::endl;

  58.         std::cout << "------------ Deserialization ------------" << std::endl;
  59.         std::istringstream stream{data};
  60.         print_sample_data(stream, std::cout);
  61.         std::cout << std::endl;
  62.     }
  63.     catch (std::exception const &e)
  64.     {
  65.         std::cerr << "Error: " << e.what() << std::endl;
  66.         return EXIT_FAILURE;
  67.     }
  68.     return EXIT_SUCCESS;
  69. }
  70. ```

Publish / Subscribe


Source code DescriptionThis is a more complicated example within redis-cpp which demonstrates how to publish messages and create a subscription to a queue. In the example a publisher and subscriber located in one process simultaniously, each one has its own stream to communicate with Redis. Usually, in real projects the publisher and subscriber are not located in one process.

  1. ``` sh
  2. // STD
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <thread>

  6. // BOOST
  7. #include <boost/thread.hpp>

  8. #include <redis-cpp/stream.h>
  9. #include <redis-cpp/execute.h>

  10. int main()
  11. {
  12.     try
  13.     {
  14.         auto const N = 100;
  15.         auto const queue_name = "test_queue";

  16.         bool volatile stopped = false;

  17.         // A message printer. The message from a queue.
  18.         auto print_message = [] (auto const &value)
  19.         {
  20.             using namespace rediscpp::resp::deserialization;
  21.             std::visit(rediscpp::resp::detail::overloaded{
  22.                    [] (bulk_string const &val)
  23.                    { std::cout << val.get() << std::endl; },
  24.                    [] (auto const &)
  25.                    { std::cout << "Unexpected value type." << std::endl; }
  26.                }, value);
  27.         };

  28.         // The subscriber is run in its own thread.
  29.         // It's some artificial example, when publisher
  30.         // and subscriber are working in one process.
  31.         // It's only for demonstration library abilities.
  32.         boost::thread subscriber{
  33.             [&stopped, &queue_name, &print_message]
  34.             {
  35.                 // Its own stream for a subscriber
  36.                 auto stream = rediscpp::make_stream("localhost", "6379");
  37.                 auto response = rediscpp::execute(*stream, "subscribe", queue_name);
  38.                 // An almost endless loop for getting messages from the queues.
  39.                 while (!stopped)
  40.                 {
  41.                     // Reading / waiting for a message.
  42.                     rediscpp::value value{*stream};
  43.                     // Message extraction.
  44.                     std::visit(rediscpp::resp::detail::overloaded{
  45.                             // We're wondered only an array in response.
  46.                             // Otherwise, there is an error.
  47.                             [&print_message] (rediscpp::resp::deserialization::array const &arr)
  48.                             {
  49.                                 std::cout << "-------- Message --------" << std::endl;
  50.                                 for (auto const &i : arr.get())
  51.                                     print_message(i);
  52.                                 std::cout << "-------------------------" << std::endl;
  53.                             },
  54.                             // Oops. An error in a response.
  55.                             [] (rediscpp::resp::deserialization::error_message const &err)
  56.                             { std::cerr << "Error: " << err.get() << std::endl; },
  57.                             // An unexpected response.
  58.                             [] (auto const &)
  59.                             { std::cout << "Unexpected value type." << std::endl; }
  60.                         }, value.get());
  61.                 }
  62.             }
  63.         };

  64.         // An artificial delay. It's not necessary in real code.
  65.         std::this_thread::sleep_for(std::chrono::milliseconds{200});

  66.         // Its own stream for a publisher.
  67.         auto stream = rediscpp::make_stream("localhost", "6379");

  68.         // The publishing N messages.
  69.         for (int i = 0 ; i < N ; ++i)
  70.         {
  71.             auto response = rediscpp::execute(*stream,
  72.                     "publish", queue_name, std::to_string(i));
  73.             std::cout << "Delivered to " << response.as<std::int64_t>()
  74.                       << " subscribers." << std::endl;
  75.         }

  76.         // An artificial delay. It's not necessary in real code.
  77.         // It's due to the artificiality of the example,
  78.         // where everything is in one process.
  79.         std::this_thread::sleep_for(std::chrono::milliseconds{200});

  80.         stopped = true;
  81.         std::this_thread::sleep_for(std::chrono::milliseconds{200});
  82.         // Why not?... Please, avoid it in real code.
  83.         // It's justified only in examples.
  84.         subscriber.interrupt();
  85.     }
  86.     catch (std::exception const &e)
  87.     {
  88.         std::cerr << "Error: " << e.what() << std::endl;
  89.         return EXIT_FAILURE;
  90.     }
  91.     return EXIT_SUCCESS;
  92. }
  93. ```

Conclusion


Take a look at a code above one more time. I hope you can find something useful for your own projects with Redis. I'd thought about adding one more level to wrap all Redis commands and refused this idea. A lot of useless work with a small outcome, because, in many cases we need to run only a handful of commands. Maybe it'll be a good idea in the future. Now you can use redis-cpp like lightweight library to execute Redis commands and get results  with minimal effort.

Enjoy your own projects with Redis!
Last Updated: 2023-09-03 19:17:54