✔︎Pickup
hiredisを使ったgetがnullしか取得できずハマった話

c言語からredisにアクセスする方法を調べてみると,hiredisというツールを使ってアクセスすることができると記載があったので,試してみることにした。

redisサーバの準備

redisサーバの構築方法は省略します

redisサーバを準備して,中身が空であることを確認します

hiredisの準備

注意,本手順で実行する場合はredisの値がgetができませんのでご注意ください。

git clone https://github.com/redis/hiredis.git
cd hiredis/
make
make install

redisへアクセスするサンプルコードをコンパイルする

サンプルコードを用意する

#include <stdio.h>
#include <hiredis/hiredis.h>
#include <stdlib.h>

extern int main(int argc, char **argv) {
  redisContext *con;
  redisReply *rep;
  int i;

  /* 接続 */
  con = redisConnect("127.0.0.1", 6379);
  if (!con) {
    fprintf(stderr, "redisConnect error\n");
    return -1;
  }
  if (con->err) {
    fprintf(stderr, "%s\n", con->errstr);
    redisFree(con);
    return -1;
  }

  /* テスト用データの設定 */
  for (i = 1; i <= 3; i++) {
    (redisReply *)redisCommand(con, "SET KEY-%d VALUE-%d", i,i);
  }

  /* データ表示 */
  for (i = 1; i <= 3; i++) {
    rep = (redisReply *)redisCommand(con, "GET KEY-%d", i);
    if (!rep) {
      fprintf(stderr, "redisReply error\n");
      redisFree(con);
      return -1;
    }
    if (rep->type != REDIS_REPLY_ERROR) {
      printf("KEY-%d = %s\n", i, rep->str);
    }
    freeReplyObject(rep);
  }

  /* 終了 */
  redisFree(con);
  return 0;
}

コンパイルする

gcc -o redis redistest.c -lhiredis

"error while loading shared libraries: libhiredis.so.1.1.1-dev: cannot open shared object file: No such file or directory"というエラーが発生した。

libhiredis.so.1.1.1-devが見つからず,解決できなかったと思い,以下のコマンドで追加

sudo apt-get install libhiredis-dev

再度以下のコマンドでコンパイルするとコンパイルができました。

gcc -o redis redistest.c -lhiredis

試しに実行してみるとnullが返ってきました。

redisの方でコマンドで確認してみると値は入っていることがわかる。

何故かhiredisの方から値が取得できていない。

調査

コンパイルされているバイナリに何がリンクされているのかを確認する

lddコマンドを使って中身を見てみます。

"error while loading shared libraries: libhiredis.so.1.1.1-dev: cannot open shared object file: No such file or directory"というエラーが発生した時のバイナリ

リンク先が"not fount"になっていました。これなら当然動かないなと納得しました。

値が取得できないときのバイナリ

リンクを見てみると"libhiredis.so.0.14"がリンクされていました

指定されているフォルダを見に行くとlibhiredis.soがlibhiredis.so.0.14にシンボリックリンクが張られていました。

gccのコンパイルオプションで-lhiredisを指定して実行すると,該当のファイルを検索して一致した場合にリンクが行われるようになります。以下のコマンドを実行してから別のlibhiredisが参照されていました

sudo apt-get install libhiredis-dev

おそらくhiredisが上記のlibhiredis-devのinstallで入れ替わったのだと思います。

hiredisのgithubを確認してみると,0.14より1.1.1の方が新しいことがわかったので,

"libhiredis.so.1.1.1-dev"を直接参照して試してみることにする。

libhiredis.so.1.1.1-devを以下のコマンドで検索した

find / -name libhiredis.so.1.1.1-dev

その結果,/usr/local/libに配置されていることがわかった。

直接パスを指定して,libhiredis.soをリンクしてみることにする。

gcc -o redis redistest.c -lhiredis -L/usr/local/lib

結果は以下のようになった。

再度実行すると値が取得することが可能になった。

結果のまとめ

libhiredis.so.0.14がリンクされている場合,setすることは可能だがgetするとnullが取得されてしまった。

libhiredis.so.0.14がリンクされているところをlibhiredis.so.1.1.1-devにすることで値が取得することが可能になった。

libhiredis.so.0.14がリンクされているときにgetすると値がnullになるかは現在のところ不明だが,回避方法としてここにまとめておきます。

追記

apt-get install libhiredis-devが問題だと思い,removeしてみた

sudo apt-get remove libhiredis-dev

再度 gcc で-lhiredisを実行すると"not found"ではなくpathが通ってリンクされていた。

libhiredis-devしたことでpathが通ったものと考えられる。

Cでバイナリを作成する際にはリンク先が正しいことを確認していかないといけないと改めて認識された件でした。

ブログ村リンク
ポチッと押してね!フォローもしてね!

ブログランキング・にほんブログ村へ
にほんブログ村
おすすめの記事