Windows 7下vc2010编译使用redis 3.0

Windows 7下vc2010编译使用redis 3.0

项目中,有多台机器频繁读写、同步一些参数。起初的方案是通过MySQL的临时表实现,对效率有一些影响,故改为redis方案。项目中redis和web、mysql是linux平台,客户端是windows 7平台C++应用进程、操作LoRa等硬件设备。

1. 编译hiredis

按网络上多篇博文的描述,C++环境下访问redis需要使用hiredis库。从下载的redis3.0源代码中发现,hiredis已集成在了项目中,如下是redis3.0的目录结构:
├─deps
├─msvs
│ ├─hiredis
│ ├─lua
│ ├ ……
│ ├─Samples
│ ├─setups
│ └─tools
├─src
│ └─Win32_Interop
├─tests
└─utils

其中,msvc目录下有个hiredis.vcxproj文件,src目录下有Win32_Interop.vcxproj文件,这两个是C++客户端需要调用的库文件。

注意,这两个.vcxproj工程是vc2012版本的,源码使用了一些Cxx11的语法,如自动推导、变长参数模板、常量成员赋值等,因此,需要对源代码做一些小改动。

1.1 编译Win32_Interop.vcxproj

添加到解决方案中,然后,在“属性->平台属性->常规”中将“平台工具集”由v120变更为v100,“配置类型”为“静态库(.lib)”;
编译,报告大量的编译错误。别紧张,这些错误其实都有共性,用vim正则表达式替换下就好。

(1) 对vector直接初始化赋值的小改动

Win32_CommandLine.cpp中,有如下代码:

static RedisParamterMapper g_redisArgMap = {...};

解决:
写个loader类,在其构造函数中对该变量赋值,然后,定义一个全局的loader变量,例如;

class g_redisArgMap_loader {
public:
	g_redisArgMap_loader() 
	{
		// QFork flags
		g_redisArgMap.insert(std::pair(cQFork,	&fp2));	// qfork [QForkControlMemoryMap handle] [parent process id]
		...
	}
	...
};
static g_redisArgMap_loader g_redisArgMap_loader_object = g_redisArgMap_loader();

(2) for(auto …)语句

for (auto p : sentinelSubCommands) {...}
解决:
for (vector::iterator p = sentinelSubCommands.begin(); p != sentinelSubCommands.end(); p++) {...}

(3) 变长参数模板(dllfunctor_stdcall)

这个解决起来也不麻烦,在win32_variadicfunctor.h中注释掉dllfunctor_stdcall的定义,然后,由vim写正则式,将代码作如下的替换:

原始代码:
auto f_WSACleanup = dllfunctor_stdcall("ws2_32.dll", "WSACleanup");
替换后的代码:
int (WSAAPI * f_WSACleanup)( void ) =  (int(\_\_stdcall * )())DLLMap::getInstance().getProcAddress("ws2\_32.dll", "WSACleanup");
vim正则式:
:%s/auto\s*\(\w\+\)\s* = dllfunctor_\w\+<\([^>,]\+\),*\s*\([^>]\+\)>/\2 (WSAAPI * \1)(\3) =  (\2(__stdcall *)(\3))DLLMap::getInstance().getProcAddress/gc

其它小问题,自行解决即可。

编译成功,生成Win32_Interop.lib文件。

1.2 编译hiredis.vcxproj

添加到解决方案中,在“属性->平台属性->常规”中将“平台工具集”由v120变更为v100,“配置类型”变更为“静态库(.lib)”;
在“附加包含目录”中添加“$(ProjectDir)…\src\Win32_Interop”;
编译,报告找不到winapifamily.h文件。

(1) 对源代码做小改动

如前所述,redis3.0中的hiredis.vcxproj是vc2012以上版本支持windows 8.x的,而winapifamily.h是WDK 8(Windows driver Kit)中的头文件。这里,我们需要对源代码做一些小改动。
在文件“redis-3.0\src\win32_interop\ws2tcpip.h”中,添加如下代码:

#define PICEA_12345_INCLUDED		1

#if (PICEA_12345_INCLUDED)
#ifndef _Outptr_					// SAL2.0中的宏,vc2010的SAL1.0中未定义
	#define _Outptr_
#endif
#ifndef _In_reads_bytes_			// SAL2.0中的宏,vc2010的SAL1.0中未定义,写个假的
	#define _In_reads_bytes_(a)
#endif
#ifndef _Out_writes_opt_			// SAL2.0中的宏,vc2010的SAL1.0中未定义,写个假的
	#define _Out_writes_opt_(a)
#endif
#endif

#if (PICEA_12345_INCLUDED || WINVER <= _WIN32_WINNT_WS03)
	#include "win32_winapifamily.h"
#else
	#include 
#endif

(2) 编译

编译成功,生成hiredis.lib文件。

1.3 编译libjemalloc、lua、RedisBenchmark等

这些库都是.c文件。
若出现“宏定义”错误,在文件开头添加#include 可解决;

若出现变量声明错误,是因为vc2010的编译器不允许c函数语句中间有变量的声明,例如:

void f(void) {
	if (...) { /*statement*/ ... }
	int i;	//这里vc2010会报告错误
	i=0;
}
解决方法: 将变量声明在函数开头即可

特别地,Cxx11/VC2013中才有的isnan和isinf等函数,在网上自己找一个,添加到工程中就可以了(我是写了个vc2010-porting.cpp文件,添加到工程中)。

1.4 编译RedisCli、RedisCheckAof等

这几个工程是RedisServer不依赖的,编译不编译没有影响。
处理方法同1.3。

1.5 编译RedisServer

对源代码的改动同1.1和1.3,并添加vc2010-porting.cpp处理isnan等函数。
然后,编译通过。
按F5调试,出现redis启动窗口

2. 使用hiredis

新建一个win32项目,然后,右键项目名,属性->配置属性->VC++ 目录->包含目录,将hiredis的路径加入进去
$(SolutionDir)redis-3.0\deps\hiredis

右键项目名->属性->配置属性->VC++目录->库目录,将hiredis.lib和Win32_Interop.lib的路径加入进去
( S o l u t i o n D i r ) (SolutionDir) (SolutionDir)(Configuration)\

右键项目名->属性->链接器->输入->附加依赖项,添加hiredis.lib、Win32_Interop和ws2_32.lib

示例代码 (测试通过)

#include 
#include 
#include 
#include 

extern "C"
{
//#include 
}

#include 
#include 

#define REDIS_SERVER_IP		"192.168.x.x"
#define REDIS_SERVER_PORT	6379
#define REDIS_SERVER_PASS	"xxxxxx"

#pragma comment(lib, "ws2_32.lib")

using namespace std;

void redis_test_proc()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 1), &wsaData);

	redisContext * redis_ctx_;
	redisReply *reply;
	struct timeval timeout = { 1, 500000 }; // 1.5 seconds

	redis_ctx_ = redisConnectWithTimeout((char*)REDIS_SERVER_IP, REDIS_SERVER_PORT, timeout);
	if (NULL != redis_ctx_ && redis_ctx_->err) {
		printf("Connection error: %s\n", redis_ctx_->errstr);
		exit(1);
	}

	reply = (redisReply *)redisCommand(redis_ctx_, "auth "REDIS_SERVER_PASS);
	if (REDIS_REPLY_ERROR == reply->type) {
		printf("Authentication failed: %s\n", reply->str);
	}
	freeReplyObject(reply);

	/* Set a key */
	reply = (redisReply *)redisCommand(redis_ctx_, "SET %s %s", "foo", "kivifriut is delicious ...");
	if (REDIS_REPLY_ERROR == reply->type) {
		printf("SET failed (%s:%d): %s\n", __FUNCTION__, __LINE__, reply->str);
		// TODO: 延迟x秒重连
	} else {
		printf("SET foo: %s\n", reply->str);
	}
	freeReplyObject(reply);


	/* Try a GET and two INCR */
	reply = (redisReply *)redisCommand(redis_ctx_, "GET foo");
	printf("GET foo: %s\n", reply->str);
	freeReplyObject(reply);

	redisFree(redis_ctx_);
}
int main(int argc, _TCHAR* argv[])
{
	redis_test_proc();
	system("pause");
	return 0;
}

输出:

SET foo: OK
GET foo: kivifriut is delicious ...
请按任意键继续. . .

源代码:
https://download.csdn.net/download/hylaking/10729376

你可能感兴趣的:(Windows,数据库)