一、编译报错 LNK1169、LNK2005
项目的dbsdk
使用了redis+python+mysql
的存储方案.
在编译hiredis库的时候,win32_interop.lib
与项目中原有的net.lib
有编译冲突。net.lib
引用了ws2_32.lib
,win32_interop.lib
也包含了ws2_32.lib
。这样当项目同时引用net.lib
和win32_interop.lib
时,就会出现重定义的LNK错误。
例如图中的使用tcp
的几个接口:accept()、bind()
。
解决方案 :
- 修改了hiredis的源码,hiredis.lib和win32_interop.lib的源代码中,但凡使用了tcp网络接口的地方,都将函数重命名。例如bind()、accept()接口全部加了前缀redis_,变为redis_bind()、redis_accept()。再重新编译导出win32_interop.lib。放入工程中,编译正常通过。
- 修改完源码以后,工程编译x64版本,发现启动项目后,项目无法正常连接上redis。这里是个人遗漏引起的,原因:调用hiredis.lib的redisConnect()接口,其底层还是调用tcp的connect()接口。编译时,connect()函数没有报错,我就没有全修改,导致遗漏。索性把所有网络相关的接口,全部修改后,再编译hiredis.lib导出到工程引用后,不可连接的问题解决,可以正常连接上redis。
- x64环境下,redisCommand()执行%b参数会报错 “Out of memory”,需要将redisCommand()中int类型修改为size_t类型(还是去修改hiredis的源码,然后编译导出新的lib文件)。
因为size_t会自动识别x64和win32,在win32下是4字节,在x64是8字节。
redisCommand()中%b的长度默认类型是int,导致在win32下没有问题,但编译x64就会报错。
二、dbsdk.lib编码问题
在python
代码中,用encode(“utf-8”)
将数据转换为utf-8
格式的二进制数据。
decode()
函数将二进制数据解码为字符串。
以utf-8
编码的二进制数据,解码也要utf-8
格式,否则解析出来的数据会是乱码。
二进制数据解码为json
字符串,如果二进制数据中包含\0
,json
字符串提前截断,从而导致json
字符串和二进制数据对不上。相当于数据被截断丢失了。
json
也不支持直接存储二进制数据。
解决方案:将二进制数据用base64算法编码为字符串,这样就可以存储到json中,进而将组装的json数据存储到redis中。
dbsdk.lib
从redis
中取出base64
编码后的json字符串。在dbsdk层同样用base64
解码json
字符串。在转换回二进制数据。
python:blob
> base64 > string > json > redis
dbsdk : redis > json > string > base64 > blob
三、hiredis库的高并发
之前dbsdk调用的hiredis的同步接口redisCommand(),当一帧存储100个玩家的时候,同步接口会阻塞挂起线程,导致服务器无法响应客户端的请求。有两个方案:
- dbsdk不再调用同步接口,改为调用异步接口redisAsyncCommand()。
- 在dbsdk开一条写线程,专门负责和redis交互,和游戏主线程独立开。这样也不会卡住game_server。
这里采用的方案一,主要是不想重复造轮子,而且不一定写的有人家好。
异步接口在linux下支持比较完善,redis提供了epoll模型。
但是在redis不怎么支持windows环境。需要另外找一个win32_interop的工程,貌似是微软自己去支持的redis(卑微)。