{"id":13396399,"url":"https://github.com/redis/hiredis","last_synced_at":"2025-05-13T16:03:29.692Z","repository":{"id":912734,"uuid":"673267","full_name":"redis/hiredis","owner":"redis","description":"Minimalistic C client for Redis \u003e= 1.2","archived":false,"fork":false,"pushed_at":"2025-04-23T11:16:52.000Z","size":1689,"stargazers_count":6383,"open_issues_count":73,"forks_count":1831,"subscribers_count":295,"default_branch":"master","last_synced_at":"2025-04-29T14:27:31.803Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2010-05-18T15:10:01.000Z","updated_at":"2025-04-29T03:11:12.000Z","dependencies_parsed_at":"2023-07-06T11:01:20.979Z","dependency_job_id":"3e2be414-da2f-4495-b084-97cce799a7ad","html_url":"https://github.com/redis/hiredis","commit_stats":{"total_commits":915,"total_committers":192,"mean_commits":4.765625,"dds":0.6688524590163935,"last_synced_commit":"8d8703ee6149ffd3b38cebedd71ad8d1fac63cc7"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fhiredis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fhiredis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fhiredis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fhiredis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redis","download_url":"https://codeload.github.com/redis/hiredis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252271396,"owners_count":21721648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T18:00:50.006Z","updated_at":"2025-05-05T22:46:21.650Z","avatar_url":"https://github.com/redis.png","language":"C","readme":"\n[![Build Status](https://github.com/redis/hiredis/actions/workflows/build.yml/badge.svg)](https://github.com/redis/hiredis/actions/workflows/build.yml)\n\n**This Readme reflects the latest changed in the master branch. See [v1.0.0](https://github.com/redis/hiredis/tree/v1.0.0) for the Readme and documentation for the latest release ([API/ABI history](https://abi-laboratory.pro/?view=timeline\u0026l=hiredis)).**\n\n# HIREDIS\n\nHiredis is a minimalistic C client library for the [Redis](https://redis.io/) database.\n\nIt is minimalistic because it just adds minimal support for the protocol, but\nat the same time it uses a high level printf-alike API in order to make it\nmuch higher level than otherwise suggested by its minimal code base and the\nlack of explicit bindings for every Redis command.\n\nApart from supporting sending commands and receiving replies, it comes with\na reply parser that is decoupled from the I/O layer. It\nis a stream parser designed for easy reusability, which can for instance be used\nin higher level language bindings for efficient reply parsing.\n\nHiredis only supports the binary-safe Redis protocol, so you can use it with any\nRedis version \u003e= 1.2.0.\n\nThe library comes with multiple APIs. There is the\n*synchronous API*, the *asynchronous API* and the *reply parsing API*.\n\n## Upgrading to \u003e 1.2.0 (**PRERELEASE**)\n\n* After v1.2.0 we modified how we invoke `poll(2)` to wait for connections to complete, such that we will now retry\n  the call if it is interrupted by a signal until:\n\n  a) The connection succeeds or fails.\n  b) The overall connection timeout is reached.\n\n  In previous versions, an interrupted `poll(2)` call would cause the connection to fail\n  with `c-\u003eerr` set to `REDIS_ERR_IO` and `c-\u003eerrstr` set to `poll(2): Interrupted system call`.\n\n## Upgrading to `1.1.0`\n\nAlmost all users will simply need to recompile their applications against the newer version of hiredis.\n\n**NOTE**:  Hiredis can now return `nan` in addition to `-inf` and `inf` in a `REDIS_REPLY_DOUBLE`.\n           Applications that deal with `RESP3` doubles should make sure to account for this.\n\n## Upgrading to `1.0.2`\n\n\u003cspan style=\"color:red\"\u003eNOTE:  v1.0.1 erroneously bumped SONAME, which is why it is skipped here.\u003c/span\u003e\n\nVersion 1.0.2 is simply 1.0.0 with a fix for [CVE-2021-32765](https://github.com/redis/hiredis/security/advisories/GHSA-hfm9-39pp-55p2).  They are otherwise identical.\n\n## Upgrading to `1.0.0`\n\nVersion 1.0.0 marks the first stable release of Hiredis.\nIt includes some minor breaking changes, mostly to make the exposed API more uniform and self-explanatory.\nIt also bundles the updated `sds` library, to sync up with upstream and Redis.\nFor code changes see the [Changelog](CHANGELOG.md).\n\n_Note:  As described below, a few member names have been changed but most applications should be able to upgrade with minor code changes and recompiling._\n\n## IMPORTANT:  Breaking changes from `0.14.1` -\u003e `1.0.0`\n\n* `redisContext` has two additional members (`free_privdata`, and `privctx`).\n* `redisOptions.timeout` has been renamed to `redisOptions.connect_timeout`, and we've added `redisOptions.command_timeout`.\n* `redisReplyObjectFunctions.createArray` now takes `size_t` instead of `int` for its length parameter.\n\n## IMPORTANT:  Breaking changes when upgrading from 0.13.x -\u003e 0.14.x\n\nBulk and multi-bulk lengths less than -1 or greater than `LLONG_MAX` are now\nprotocol errors. This is consistent with the RESP specification. On 32-bit\nplatforms, the upper bound is lowered to `SIZE_MAX`.\n\nChange `redisReply.len` to `size_t`, as it denotes the the size of a string\n\nUser code should compare this to `size_t` values as well.  If it was used to\ncompare to other values, casting might be necessary or can be removed, if\ncasting was applied before.\n\n## Upgrading from `\u003c0.9.0`\n\nVersion 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing\ncode using hiredis should not be a big pain. The key thing to keep in mind when\nupgrading is that hiredis \u003e= 0.9.0 uses a `redisContext*` to keep state, in contrast to\nthe stateless 0.0.1 that only has a file descriptor to work with.\n\n## Synchronous API\n\nTo consume the synchronous API, there are only a few function calls that need to be introduced:\n\n```c\nredisContext *redisConnect(const char *ip, int port);\nvoid *redisCommand(redisContext *c, const char *format, ...);\nvoid freeReplyObject(void *reply);\n```\n\n### Connecting\n\nThe function `redisConnect` is used to create a so-called `redisContext`. The\ncontext is where Hiredis holds state for a connection. The `redisContext`\nstruct has an integer `err` field that is non-zero when the connection is in\nan error state. The field `errstr` will contain a string with a description of\nthe error. More information on errors can be found in the **Errors** section.\nAfter trying to connect to Redis using `redisConnect` you should\ncheck the `err` field to see if establishing the connection was successful:\n\n```c\nredisContext *c = redisConnect(\"127.0.0.1\", 6379);\nif (c == NULL || c-\u003eerr) {\n    if (c) {\n        printf(\"Error: %s\\n\", c-\u003eerrstr);\n        // handle error\n    } else {\n        printf(\"Can't allocate redis context\\n\");\n    }\n}\n```\n\nOne can also use `redisConnectWithOptions` which takes a `redisOptions` argument\nthat can be configured with endpoint information as well as many different flags\nto change how the `redisContext` will be configured.\n\n```c\nredisOptions opt = {0};\n\n/* One can set the endpoint with one of our helper macros */\nif (tcp) {\n    REDIS_OPTIONS_SET_TCP(\u0026opt, \"localhost\", 6379);\n} else {\n    REDIS_OPTIONS_SET_UNIX(\u0026opt, \"/tmp/redis.sock\");\n}\n\n/* And privdata can be specified with another helper */\nREDIS_OPTIONS_SET_PRIVDATA(\u0026opt, myPrivData, myPrivDataDtor);\n\n/* Finally various options may be set via the `options` member, as described below */\nopt-\u003eoptions |= REDIS_OPT_PREFER_IPV4;\n```\n\nIf a connection is lost, `int redisReconnect(redisContext *c)` can be used to restore the connection using the same endpoint and options as the given context.\n\n### Configurable redisOptions flags\n\nThere are several flags you may set in the `redisOptions` struct to change default behavior.  You can specify the flags via the `redisOptions-\u003eoptions` member.\n\n| Flag | Description  |\n| --- | --- |\n| REDIS\\_OPT\\_NONBLOCK | Tells hiredis to make a non-blocking connection. |\n| REDIS\\_OPT\\_REUSEADDR | Tells hiredis to set the [SO_REUSEADDR](https://man7.org/linux/man-pages/man7/socket.7.html) socket option |\n| REDIS\\_OPT\\_PREFER\\_IPV4\u003cbr\u003eREDIS\\_OPT\\_PREFER_IPV6\u003cbr\u003eREDIS\\_OPT\\_PREFER\\_IP\\_UNSPEC | Informs hiredis to either prefer IPv4 or IPv6 when invoking [getaddrinfo](https://man7.org/linux/man-pages/man3/gai_strerror.3.html).  `REDIS_OPT_PREFER_IP_UNSPEC` will cause hiredis to specify `AF_UNSPEC` in the getaddrinfo call, which means both IPv4 and IPv6 addresses will be searched simultaneously.\u003cbr\u003eHiredis prefers IPv4 by default. |\n| REDIS\\_OPT\\_NO\\_PUSH\\_AUTOFREE | Tells hiredis to not install the default RESP3 PUSH handler (which just intercepts and frees the replies).  This is useful in situations where you want to process these messages in-band. |\n| REDIS\\_OPT\\_NOAUTOFREEREPLIES | **ASYNC**: tells hiredis not to automatically invoke `freeReplyObject` after executing the reply callback. |\n| REDIS\\_OPT\\_NOAUTOFREE | **ASYNC**: Tells hiredis not to automatically free the `redisAsyncContext` on connection/communication failure, but only if the user makes an explicit call to `redisAsyncDisconnect` or `redisAsyncFree` |\n\n*Note: A `redisContext` is not thread-safe.*\n\n### Other configuration using socket options\n\nThe following socket options are applied directly to the underlying socket.\nThe values are not stored in the `redisContext`, so they are not automatically applied when reconnecting using `redisReconnect()`.\nThese functions return `REDIS_OK` on success.\nOn failure, `REDIS_ERR` is returned and the underlying connection is closed.\n\nTo configure these for an asynchronous context (see *Asynchronous API* below), use `ac-\u003ec` to get the redisContext out of an asyncRedisContext.\n\n```C\nint redisEnableKeepAlive(redisContext *c);\nint redisEnableKeepAliveWithInterval(redisContext *c, int interval);\n```\n\nEnables TCP keepalive by setting the following socket options (with some variations depending on OS):\n\n* `SO_KEEPALIVE`;\n* `TCP_KEEPALIVE` or `TCP_KEEPIDLE`, value configurable using the `interval` parameter, default 15 seconds;\n* `TCP_KEEPINTVL` set to 1/3 of `interval`;\n* `TCP_KEEPCNT` set to 3.\n\n```C\nint redisSetTcpUserTimeout(redisContext *c, unsigned int timeout);\n```\n\nSet the `TCP_USER_TIMEOUT` Linux-specific socket option which is as described in the `tcp` man page:\n\n\u003e When the value is greater than 0, it specifies the maximum amount of time in milliseconds that trans mitted data may remain unacknowledged before TCP will forcibly close the corresponding connection and return ETIMEDOUT to the application.\n\u003e If the option value is specified as 0, TCP will use the system default.\n\n### Sending commands\n\nThere are several ways to issue commands to Redis. The first that will be introduced is\n`redisCommand`. This function takes a format similar to printf. In the simplest form,\nit is used like this:\n```c\nreply = redisCommand(context, \"SET foo bar\");\n```\n\nThe specifier `%s` interpolates a string in the command, and uses `strlen` to\ndetermine the length of the string:\n```c\nreply = redisCommand(context, \"SET foo %s\", value);\n```\nWhen you need to pass binary safe strings in a command, the `%b` specifier can be\nused. Together with a pointer to the string, it requires a `size_t` length argument\nof the string:\n```c\nreply = redisCommand(context, \"SET foo %b\", value, (size_t) valuelen);\n```\nInternally, Hiredis splits the command in different arguments and will\nconvert it to the protocol used to communicate with Redis.\nOne or more spaces separates arguments, so you can use the specifiers\nanywhere in an argument:\n```c\nreply = redisCommand(context, \"SET key:%s %s\", myid, value);\n```\n\n### Using replies\n\nThe return value of `redisCommand` holds a reply when the command was\nsuccessfully executed. When an error occurs, the return value is `NULL` and\nthe `err` field in the context will be set (see section on **Errors**).\nOnce an error is returned the context cannot be reused and you should set up\na new connection.\n\nThe standard replies that `redisCommand` are of the type `redisReply`. The\n`type` field in the `redisReply` should be used to test what kind of reply\nwas received:\n\n### RESP2\n\n* **`REDIS_REPLY_STATUS`**:\n    * The command replied with a status reply. The status string can be accessed using `reply-\u003estr`.\n      The length of this string can be accessed using `reply-\u003elen`.\n\n* **`REDIS_REPLY_ERROR`**:\n    *  The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.\n\n* **`REDIS_REPLY_INTEGER`**:\n    * The command replied with an integer. The integer value can be accessed using the\n      `reply-\u003einteger` field of type `long long`.\n\n* **`REDIS_REPLY_NIL`**:\n    * The command replied with a **nil** object. There is no data to access.\n\n* **`REDIS_REPLY_STRING`**:\n    * A bulk (string) reply. The value of the reply can be accessed using `reply-\u003estr`.\n      The length of this string can be accessed using `reply-\u003elen`.\n\n* **`REDIS_REPLY_ARRAY`**:\n    * A multi bulk reply. The number of elements in the multi bulk reply is stored in\n      `reply-\u003eelements`. Every element in the multi bulk reply is a `redisReply` object as well\n      and can be accessed via `reply-\u003eelement[..index..]`.\n      Redis may reply with nested arrays but this is fully supported.\n\n### RESP3\n\nHiredis also supports every new `RESP3` data type which are as follows.  For more information about the protocol see the `RESP3` [specification.](https://github.com/antirez/RESP3/blob/master/spec.md)\n\n* **`REDIS_REPLY_DOUBLE`**:\n    * The command replied with a double-precision floating point number.\n      The value is stored as a string in the `str` member, and can be converted with `strtod` or similar.\n\n* **`REDIS_REPLY_BOOL`**:\n    * A boolean true/false reply.\n      The value is stored in the `integer` member and will be either `0` or `1`.\n\n* **`REDIS_REPLY_MAP`**:\n    * An array with the added invariant that there will always be an even number of elements.\n      The MAP is functionally equivalent to `REDIS_REPLY_ARRAY` except for the previously mentioned invariant.\n\n* **`REDIS_REPLY_SET`**:\n    * An array response where each entry is unique.\n      Like the MAP type, the data is identical to an array response except there are no duplicate values.\n\n* **`REDIS_REPLY_PUSH`**:\n    * An array that can be generated spontaneously by Redis.\n      This array response will always contain at least two subelements.  The first contains the type of `PUSH` message (e.g. `message`, or `invalidate`), and the second being a sub-array with the `PUSH` payload itself.\n\n* **`REDIS_REPLY_ATTR`**:\n    * An array structurally identical to a `MAP` but intended as meta-data about a reply.\n      _As of Redis 6.0.6 this reply type is not used in Redis_\n\n* **`REDIS_REPLY_BIGNUM`**:\n    * A string representing an arbitrarily large signed or unsigned integer value.\n      The number will be encoded as a string in the `str` member of `redisReply`.\n\n* **`REDIS_REPLY_VERB`**:\n    * A verbatim string, intended to be presented to the user without modification.\n      The string payload is stored in the `str` member, and type data is stored in the `vtype` member (e.g. `txt` for raw text or `md` for markdown).\n\nReplies should be freed using the `freeReplyObject()` function.\nNote that this function will take care of freeing sub-reply objects\ncontained in arrays and nested arrays, so there is no need for the user to\nfree the sub replies (it is actually harmful and will corrupt the memory).\n\n**Important:** the current version of hiredis (1.0.0) frees replies when the\nasynchronous API is used. This means you should not call `freeReplyObject` when\nyou use this API. The reply is cleaned up by hiredis _after_ the callback\nreturns.  We may introduce a flag to make this configurable in future versions of the library.\n\n### Cleaning up\n\nTo disconnect and free the context the following function can be used:\n```c\nvoid redisFree(redisContext *c);\n```\nThis function immediately closes the socket and then frees the allocations done in\ncreating the context.\n\n### Sending commands (continued)\n\nTogether with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.\nIt has the following prototype:\n```c\nvoid *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);\n```\nIt takes the number of arguments `argc`, an array of strings `argv` and the lengths of the\narguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will\nuse `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments\nneed to be binary safe, the entire array of lengths `argvlen` should be provided.\n\nThe return value has the same semantic as `redisCommand`.\n\n### Pipelining\n\nTo explain how Hiredis supports pipelining in a blocking connection, there needs to be\nunderstanding of the internal execution flow.\n\nWhen any of the functions in the `redisCommand` family is called, Hiredis first formats the\ncommand according to the Redis protocol. The formatted command is then put in the output buffer\nof the context. This output buffer is dynamic, so it can hold any number of commands.\nAfter the command is put in the output buffer, `redisGetReply` is called. This function has the\nfollowing two execution paths:\n\n1. The input buffer is non-empty:\n    * Try to parse a single reply from the input buffer and return it\n    * If no reply could be parsed, continue at *2*\n2. The input buffer is empty:\n    * Write the **entire** output buffer to the socket\n    * Read from the socket until a single reply could be parsed\n\nThe function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply\nis expected on the socket. To pipeline commands, the only thing that needs to be done is\nfilling up the output buffer. For this cause, two commands can be used that are identical\nto the `redisCommand` family, apart from not returning a reply:\n```c\nvoid redisAppendCommand(redisContext *c, const char *format, ...);\nvoid redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);\n```\nAfter calling either function one or more times, `redisGetReply` can be used to receive the\nsubsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where\nthe latter means an error occurred while reading a reply. Just as with the other commands,\nthe `err` field in the context can be used to find out what the cause of this error is.\n\nThe following examples shows a simple pipeline (resulting in only a single call to `write(2)` and\na single call to `read(2)`):\n```c\nredisReply *reply;\nredisAppendCommand(context,\"SET foo bar\");\nredisAppendCommand(context,\"GET foo\");\nredisGetReply(context,(void**)\u0026reply); // reply for SET\nfreeReplyObject(reply);\nredisGetReply(context,(void**)\u0026reply); // reply for GET\nfreeReplyObject(reply);\n```\nThis API can also be used to implement a blocking subscriber:\n```c\nreply = redisCommand(context,\"SUBSCRIBE foo\");\nfreeReplyObject(reply);\nwhile(redisGetReply(context,(void *)\u0026reply) == REDIS_OK) {\n    // consume message\n    freeReplyObject(reply);\n}\n```\n### Errors\n\nWhen a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is\nreturned. The `err` field inside the context will be non-zero and set to one of the\nfollowing constants:\n\n* **`REDIS_ERR_IO`**:\n    There was an I/O error while creating the connection, trying to write\n    to the socket or read from the socket. If you included `errno.h` in your\n    application, you can use the global `errno` variable to find out what is\n    wrong.\n\n* **`REDIS_ERR_EOF`**:\n    The server closed the connection which resulted in an empty read.\n\n* **`REDIS_ERR_PROTOCOL`**:\n    There was an error while parsing the protocol.\n\n* **`REDIS_ERR_OTHER`**:\n    Any other error. Currently, it is only used when a specified hostname to connect\n    to cannot be resolved.\n\nIn every case, the `errstr` field in the context will be set to hold a string representation\nof the error.\n\n## Asynchronous API\n\nHiredis comes with an asynchronous API that works easily with any event library.\nExamples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)\nand [libevent](http://monkey.org/~provos/libevent/).\n\n### Connecting\n\nThe function `redisAsyncConnect` can be used to establish a non-blocking connection to\nRedis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field\nshould be checked after creation to see if there were errors creating the connection.\nBecause the connection that will be created is non-blocking, the kernel is not able to\ninstantly return if the specified host and port is able to accept a connection.\nIn case of error, it is the caller's responsibility to free the context using `redisAsyncFree()`\n\n*Note: A `redisAsyncContext` is not thread-safe.*\n\nAn application function creating a connection might look like this:\n\n```c\nvoid appConnect(myAppData *appData)\n{\n    redisAsyncContext *c = redisAsyncConnect(\"127.0.0.1\", 6379);\n    if (c-\u003eerr) {\n        printf(\"Error: %s\\n\", c-\u003eerrstr);\n        // handle error\n        redisAsyncFree(c);\n        c = NULL;\n    } else {\n        appData-\u003econtext = c;\n        appData-\u003econnecting = 1;\n        c-\u003edata = appData; /* store application pointer for the callbacks */\n        redisAsyncSetConnectCallback(c, appOnConnect);\n        redisAsyncSetDisconnectCallback(c, appOnDisconnect);\n    }\n}\n\n```\n\n\nThe asynchronous context _should_ hold a *connect* callback function that is called when the connection\nattempt completes, either successfully or with an error.\nIt _can_ also hold a *disconnect* callback function that is called when the\nconnection is disconnected (either because of an error or per user request). Both callbacks should\nhave the following prototype:\n```c\nvoid(const redisAsyncContext *c, int status);\n```\n\nOn a *connect*, the `status` argument is set to `REDIS_OK` if the connection attempt succeeded.  In this\ncase, the context is ready to accept commands.  If it is called with `REDIS_ERR` then the\nconnection attempt failed. The `err` field in the context can be accessed to find out the cause of the error.\nAfter a failed connection attempt, the context object is automatically freed by the library after calling\nthe connect callback.  This may be a good point to create a new context and retry the connection.\n\nOn a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the\nuser, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`\nfield in the context can be accessed to find out the cause of the error.\n\nThe context object is always freed after the disconnect callback fired. When a reconnect is needed,\nthe disconnect callback is a good point to do so.\n\nSetting the connect or disconnect callbacks can only be done once per context. For subsequent calls the\napi will return `REDIS_ERR`. The function to set the callbacks have the following prototype:\n```c\n/* Alternatively you can use redisAsyncSetConnectCallbackNC which will be passed a non-const\n   redisAsyncContext* on invocation (e.g. allowing writes to the privdata member). */\nint redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);\nint redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);\n```\n`ac-\u003edata` may be used to pass user data to both callbacks.  A typical implementation\nmight look something like this:\n```c\nvoid appOnConnect(redisAsyncContext *c, int status)\n{\n    myAppData *appData = (myAppData*)c-\u003edata; /* get my application specific context*/\n    appData-\u003econnecting = 0;\n    if (status == REDIS_OK) {\n        appData-\u003econnected = 1;\n    } else {\n        appData-\u003econnected = 0;\n        appData-\u003eerr = c-\u003eerr;\n        appData-\u003econtext = NULL; /* avoid stale pointer when callback returns */\n    }\n    appAttemptReconnect();\n}\n\nvoid appOnDisconnect(redisAsyncContext *c, int status)\n{\n    myAppData *appData = (myAppData*)c-\u003edata; /* get my application specific context*/\n    appData-\u003econnected = 0;\n    appData-\u003eerr = c-\u003eerr;\n    appData-\u003econtext = NULL; /* avoid stale pointer when callback returns */\n    if (status == REDIS_OK) {\n        appNotifyDisconnectCompleted(mydata);\n    } else {\n        appNotifyUnexpectedDisconnect(mydata);\n        appAttemptReconnect();\n    }\n}\n```\n\n### Sending commands and their callbacks\n\nIn an asynchronous context, commands are automatically pipelined due to the nature of an event loop.\nTherefore, unlike the synchronous API, there is only a single way to send commands.\nBecause commands are sent to Redis asynchronously, issuing a command requires a callback function\nthat is called when the reply is received. Reply callbacks should have the following prototype:\n```c\nvoid(redisAsyncContext *c, void *reply, void *privdata);\n```\nThe `privdata` argument can be used to curry arbitrary data to the callback from the point where\nthe command is initially queued for execution.\n\nThe functions that can be used to issue commands in an asynchronous context are:\n```c\nint redisAsyncCommand(\n  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,\n  const char *format, ...);\nint redisAsyncCommandArgv(\n  redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,\n  int argc, const char **argv, const size_t *argvlen);\n```\nBoth functions work like their blocking counterparts. The return value is `REDIS_OK` when the command\nwas successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection\nis being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is\nreturned on calls to the `redisAsyncCommand` family.\n\nIf the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback\nfor a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only\nvalid for the duration of the callback.\n\nAll pending callbacks are called with a `NULL` reply when the context encountered an error.\n\nFor every command issued, with the exception of **SUBSCRIBE** and **PSUBSCRIBE**, the callback is\ncalled exactly once.  Even if the context object id disconnected or deleted, every pending callback\nwill be called with a `NULL` reply.\n\nFor **SUBSCRIBE** and **PSUBSCRIBE**, the callbacks may be called repeatedly until an `unsubscribe`\nmessage arrives.  This will be the last invocation of the callback. In case of error, the callbacks\nmay receive a final `NULL` reply instead.\n\n### Disconnecting\n\nAn asynchronous connection can be terminated using:\n```c\nvoid redisAsyncDisconnect(redisAsyncContext *ac);\n```\nWhen this function is called, the connection is **not** immediately terminated. Instead, new\ncommands are no longer accepted and the connection is only terminated when all pending commands\nhave been written to the socket, their respective replies have been read and their respective\ncallbacks have been executed. After this, the disconnection callback is executed with the\n`REDIS_OK` status and the context object is freed.\n\nThe connection can be forcefully disconnected using\n```c\nvoid redisAsyncFree(redisAsyncContext *ac);\n```\nIn this case, nothing more is written to the socket, all pending callbacks are called with a `NULL`\nreply and the disconnection callback is called with `REDIS_OK`, after which the context object\nis freed.\n\n\n### Hooking it up to event library *X*\n\nThere are a few hooks that need to be set on the context object after it is created.\nSee the `adapters/` directory for bindings to *libev* and *libevent*.\n\n## Reply parsing API\n\nHiredis comes with a reply parsing API that makes it easy for writing higher\nlevel language bindings.\n\nThe reply parsing API consists of the following functions:\n```c\nredisReader *redisReaderCreate(void);\nvoid redisReaderFree(redisReader *reader);\nint redisReaderFeed(redisReader *reader, const char *buf, size_t len);\nint redisReaderGetReply(redisReader *reader, void **reply);\n```\nThe same set of functions are used internally by hiredis when creating a\nnormal Redis context, the above API just exposes it to the user for a direct\nusage.\n\n### Usage\n\nThe function `redisReaderCreate` creates a `redisReader` structure that holds a\nbuffer with unparsed data and state for the protocol parser.\n\nIncoming data -- most likely from a socket -- can be placed in the internal\nbuffer of the `redisReader` using `redisReaderFeed`. This function will make a\ncopy of the buffer pointed to by `buf` for `len` bytes. This data is parsed\nwhen `redisReaderGetReply` is called. This function returns an integer status\nand a reply object (as described above) via `void **reply`. The returned status\ncan be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went\nwrong (either a protocol error, or an out of memory error).\n\nThe parser limits the level of nesting for multi bulk payloads to 7. If the\nmulti bulk nesting level is higher than this, the parser returns an error.\n\n### Customizing replies\n\nThe function `redisReaderGetReply` creates `redisReply` and makes the function\nargument `reply` point to the created `redisReply` variable. For instance, if\nthe response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`\nwill hold the status as a vanilla C string. However, the functions that are\nresponsible for creating instances of the `redisReply` can be customized by\nsetting the `fn` field on the `redisReader` struct. This should be done\nimmediately after creating the `redisReader`.\n\nFor example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)\nuses customized reply object functions to create Ruby objects.\n\n### Reader max buffer\n\nBoth when using the Reader API directly or when using it indirectly via a\nnormal Redis context, the redisReader structure uses a buffer in order to\naccumulate data from the server.\nUsually this buffer is destroyed when it is empty and is larger than 16\nKiB in order to avoid wasting memory in unused buffers\n\nHowever when working with very big payloads destroying the buffer may slow\ndown performances considerably, so it is possible to modify the max size of\nan idle buffer changing the value of the `maxbuf` field of the reader structure\nto the desired value. The special value of 0 means that there is no maximum\nvalue for an idle buffer, so the buffer will never get freed.\n\nFor instance if you have a normal Redis context you can set the maximum idle\nbuffer to zero (unlimited) just with:\n```c\ncontext-\u003ereader-\u003emaxbuf = 0;\n```\nThis should be done only in order to maximize performances when working with\nlarge payloads. The context should be set back to `REDIS_READER_MAX_BUF` again\nas soon as possible in order to prevent allocation of useless memory.\n\n### Reader max array elements\n\nBy default the hiredis reply parser sets the maximum number of multi-bulk elements\nto 2^32 - 1 or 4,294,967,295 entries.  If you need to process multi-bulk replies\nwith more than this many elements you can set the value higher or to zero, meaning\nunlimited with:\n```c\ncontext-\u003ereader-\u003emaxelements = 0;\n```\n\n## SSL/TLS Support\n\n### Building\n\nSSL/TLS support is not built by default and requires an explicit flag:\n\n    make USE_SSL=1\n\nThis requires OpenSSL development package (e.g. including header files to be\navailable.\n\nWhen enabled, SSL/TLS support is built into extra `libhiredis_ssl.a` and\n`libhiredis_ssl.so` static/dynamic libraries. This leaves the original libraries\nunaffected so no additional dependencies are introduced.\n\n### Using it\n\nFirst, you'll need to make sure you include the SSL header file:\n\n```c\n#include \u003chiredis/hiredis.h\u003e\n#include \u003chiredis/hiredis_ssl.h\u003e\n```\n\nYou will also need to link against `libhiredis_ssl`, **in addition** to\n`libhiredis` and add `-lssl -lcrypto` to satisfy its dependencies.\n\nHiredis implements SSL/TLS on top of its normal `redisContext` or\n`redisAsyncContext`, so you will need to establish a connection first and then\ninitiate an SSL/TLS handshake.\n\n#### Hiredis OpenSSL Wrappers\n\nBefore Hiredis can negotiate an SSL/TLS connection, it is necessary to\ninitialize OpenSSL and create a context. You can do that in two ways:\n\n1. Work directly with the OpenSSL API to initialize the library's global context\n   and create `SSL_CTX *` and `SSL *` contexts. With an `SSL *` object you can\n   call `redisInitiateSSL()`.\n2. Work with a set of Hiredis-provided wrappers around OpenSSL, create a\n   `redisSSLContext` object to hold configuration and use\n   `redisInitiateSSLWithContext()` to initiate the SSL/TLS handshake.\n\n```c\n/* An Hiredis SSL context. It holds SSL configuration and can be reused across\n * many contexts.\n */\nredisSSLContext *ssl_context;\n\n/* An error variable to indicate what went wrong, if the context fails to\n * initialize.\n */\nredisSSLContextError ssl_error = REDIS_SSL_CTX_NONE;\n\n/* Initialize global OpenSSL state.\n *\n * You should call this only once when your app initializes, and only if\n * you don't explicitly or implicitly initialize OpenSSL it elsewhere.\n */\nredisInitOpenSSL();\n\n/* Create SSL context */\nssl_context = redisCreateSSLContext(\n    \"cacertbundle.crt\",     /* File name of trusted CA/ca bundle file, optional */\n    \"/path/to/certs\",       /* Path of trusted certificates, optional */\n    \"client_cert.pem\",      /* File name of client certificate file, optional */\n    \"client_key.pem\",       /* File name of client private key, optional */\n    \"redis.mydomain.com\",   /* Server name to request (SNI), optional */\n    \u0026ssl_error);\n\nif(ssl_context == NULL || ssl_error != REDIS_SSL_CTX_NONE) {\n    /* Handle error and abort... */\n    /* e.g.\n    printf(\"SSL error: %s\\n\",\n        (ssl_error != REDIS_SSL_CTX_NONE) ?\n            redisSSLContextGetError(ssl_error) : \"Unknown error\");\n    // Abort\n    */\n}\n\n/* Create Redis context and establish connection */\nc = redisConnect(\"localhost\", 6443);\nif (c == NULL || c-\u003eerr) {\n    /* Handle error and abort... */\n}\n\n/* Negotiate SSL/TLS */\nif (redisInitiateSSLWithContext(c, ssl_context) != REDIS_OK) {\n    /* Handle error, in c-\u003eerr / c-\u003eerrstr */\n}\n```\n\n## RESP3 PUSH replies\nRedis 6.0 introduced PUSH replies with the reply-type `\u003e`.  These messages are generated spontaneously and can arrive at any time, so must be handled using callbacks.\n\n### Default behavior\nHiredis installs handlers on `redisContext` and `redisAsyncContext` by default, which will intercept and free any PUSH replies detected.  This means existing code will work as-is after upgrading to Redis 6 and switching to `RESP3`.\n\n### Custom PUSH handler prototypes\nThe callback prototypes differ between `redisContext` and `redisAsyncContext`.\n\n#### redisContext\n```c\nvoid my_push_handler(void *privdata, void *reply) {\n    /* Handle the reply */\n\n    /* Note: We need to free the reply in our custom handler for\n             blocking contexts.  This lets us keep the reply if\n             we want. */\n    freeReplyObject(reply);\n}\n```\n\n#### redisAsyncContext\n```c\nvoid my_async_push_handler(redisAsyncContext *ac, void *reply) {\n    /* Handle the reply */\n\n    /* Note:  Because async hiredis always frees replies, you should\n              not call freeReplyObject in an async push callback. */\n}\n```\n\n### Installing a custom handler\nThere are two ways to set your own PUSH handlers.\n\n1. Set `push_cb` or `async_push_cb` in the `redisOptions` struct and connect with `redisConnectWithOptions` or `redisAsyncConnectWithOptions`.\n    ```c\n    redisOptions = {0};\n    REDIS_OPTIONS_SET_TCP(\u0026options, \"127.0.0.1\", 6379);\n    options-\u003epush_cb = my_push_handler;\n    redisContext *context = redisConnectWithOptions(\u0026options);\n    ```\n2.  Call `redisSetPushCallback` or `redisAsyncSetPushCallback` on a connected context.\n    ```c\n    redisContext *context = redisConnect(\"127.0.0.1\", 6379);\n    redisSetPushCallback(context, my_push_handler);\n    ```\n\n    _Note `redisSetPushCallback` and `redisAsyncSetPushCallback` both return any currently configured handler,  making it easy to override and then return to the old value._\n\n### Specifying no handler\nIf you have a unique use-case where you don't want hiredis to automatically intercept and free PUSH replies, you will want to configure no handler at all.  This can be done in two ways.\n1.  Set the `REDIS_OPT_NO_PUSH_AUTOFREE` flag in `redisOptions` and leave the callback function pointer `NULL`.\n    ```c\n    redisOptions = {0};\n    REDIS_OPTIONS_SET_TCP(\u0026options, \"127.0.0.1\", 6379);\n    options-\u003eoptions |= REDIS_OPT_NO_PUSH_AUTOFREE;\n    redisContext *context = redisConnectWithOptions(\u0026options);\n    ```\n3.  Call `redisSetPushCallback` with `NULL` once connected.\n    ```c\n    redisContext *context = redisConnect(\"127.0.0.1\", 6379);\n    redisSetPushCallback(context, NULL);\n    ```\n\n    _Note:  With no handler configured, calls to `redisCommand` may generate more than one reply, so this strategy is only applicable when there's some kind of blocking `redisGetReply()` loop (e.g. `MONITOR` or `SUBSCRIBE` workloads)._\n\n## Allocator injection\n\nHiredis uses a pass-thru structure of function pointers defined in [alloc.h](https://github.com/redis/hiredis/blob/f5d25850/alloc.h#L41) that contain the currently configured allocation and deallocation functions.  By default they just point to libc (`malloc`, `calloc`, `realloc`, etc).\n\n### Overriding\n\nOne can override the allocators like so:\n\n```c\nhiredisAllocFuncs myfuncs = {\n    .mallocFn = my_malloc,\n    .callocFn = my_calloc,\n    .reallocFn = my_realloc,\n    .strdupFn = my_strdup,\n    .freeFn = my_free,\n};\n\n// Override allocators (function returns current allocators if needed)\nhiredisAllocFuncs orig = hiredisSetAllocators(\u0026myfuncs);\n```\n\nTo reset the allocators to their default libc function simply call:\n\n```c\nhiredisResetAllocators();\n```\n\n## AUTHORS\n\nSalvatore Sanfilippo (antirez at gmail),\\\nPieter Noordhuis (pcnoordhuis at gmail)\\\nMichael Grunder (michael dot grunder at gmail)\n\n_Hiredis is released under the BSD license._\n","funding_links":[],"categories":["Uncategorized","C","Database","数据库","Database ##","Developing","Redis Client"],"sub_categories":["Uncategorized","Dependencies","C"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis%2Fhiredis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredis%2Fhiredis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis%2Fhiredis/lists"}