前端:JavaScript
后端:C++ ,openresty(lua)
功能需求:后端C++游戏服务器产生的战斗战报保存为二进制格式存入mysql数据库,客户端查看战报是通过http连接nginx的web服务器拉取。
流程:
1.C++将游戏战报信息拼接成二进制数据之后,先用zlib压缩以下,进一步减小数据体积:
compress(szZipReport, &nSize, (const unsigned char*)szReport, nLenReport);
2.我们用的是调用存储过程的方式进行mysql数据的读写的,所以还需要将压缩过的二进制数据进行格式转换,步骤类似如下:
//需要把每一个都格式化出来
string hexstr;
for( int i = 0 ; i < nSize; i++)
{
BYTE temp_char = *(szZipReport+i);
char temp_str[10] = {0};
sprintf(temp_str,"%02x",temp_char);
hexstr += temp_str;
}
3.格式化好之后就可以作为二进制参数传给存储过程了,注意二进制数据作为参数传递时,需要以0x开头,步骤类似如下:
std::string str("call p_fight_report_add(@a,%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, 0x%s);");
// 最后一个参数为二进制数据,传入的实际为字符串。
4.存入数据库之后,web服务器那边直接用sql语句获取得到的就是二进制格式的数据,我们web用的是lor(基于openresty的一个开源框架),自带有mysql接口,读取数据的代码大致如下:
local sql = "select log from "..config.database..config.tablename.." where id = "..reportid.." limit 1;"
local ok, err, errcode, sqlstate = mysql:query(sql)
if not ok then
ngx.log(ngx.ERR, "select data from db error!!!")
return ngx.exit(500)
end
5.读取之后的数据直接用zlib解压即可,由于lor的逻辑是用lua写的,当前包并没有lua版本的zlib使用,当时就使用ffi-zlib进行了ffi转换,github地址:https://github.com/hamishforbes/lua-ffi-zlib
解压缩代码大致如下:
local strLog = ok[1].log
local input = function(bufsize)
local d = strLog
ngx.log(ngx.ERR, "decompress input data = "..d)
return d
end
local output_table = {}
local output = function(data)
table.insert(output_table, data)
end
-- Decompress the data
local ok, err = zlib.inflateGzip(input, output)
if not ok then
ngx.log(ngx.ERR, "decompress data error!"..err)
res:status(500):send("decompress data error!")
return
end
local realRes = table.concat(output_table,'')
-- realRes为解压出来的二进制数据
res:send(realRes, 'application/gif')
6.客户端JavaScript这边用的是cocos creator引擎,获取并解析为arraybuffer的代码如下:
requestReport(url, succ, fail) {
let xhr = cc.loader.getXMLHttpRequest()
let self = this
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && (xhr.status >= 200 && xhr.status < 400)) {
// let response = xhr.responseText;
let response = xhr.response;
let reader = new FileReader();
// response为blob对象
reader.readAsArrayBuffer(response);
reader.onload = (e) => {
if (succ) {
succ(reader.result) // reader.result 为arrayBuffer
}
}
} else if (fail) {
fail()
}
};
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.send();
},