先说结论,细节待补充。
目前发现两处问题:
1、Raknet自带的AutoPatcher服务器,初始化DB时有一句:
"modificationDate double precision DEFAULT EXTRACT(EPOCH ......),"
(AutopatcherMySQLRepository.cpp Line 83)
根据百度来的说法,MySQL不支持以函数作为默认值。所以这个地方运行时会报错,我将其改为DEFAULT 0.0,然后修改代码。
具体是在同一个文件两处调用“INSERT INTO FileVersionHistory”的时候,显式的给modificationDate赋值,利用C语言标准库的time.h获得当前时间放进去就可以了。
这么以来,数据库表创建似乎是ok了,但发现下载不了。
2、客户端下载patcher时,每次服务器传来的都是0字节数据,根本不能下载。
Raknet代码还是挺复杂的,连续调试了两三天代码,发现问题还是出在 AutopatcherMySQLRepository.cpp 这个文件,下面这句:
sprintf(query, "SELECT substring(content from %i for %i) FROM FileVersionHistory WHERE fileId=%i;", startReadBytes+1,numBytesToRead,context.fileId);
这句查询会失败,原因还不清楚。晚上或者明天补充一下。
———————————咚咚咚,次日—————————————————————————————————————————————————————————
AutoPatcher不能用的问题基本搞定了,先说结论:Raknet底层操作MySQL数据库时,连接用的参数处理不当,导致在Linux下二次连接数据库会失败。
遇到复杂问题都得先从基本程序开始做做试验:
//我自己写的测试代码:
#include "MySQLInterface.h"
#include <stdio.h>
#include "mysql/mysql.h" // MYSQL_RES
int main()
{
MySQLInterface sql;
bool success = sql.Connect("localhost", "root", "1", "swift", 0, NULL, 0);
if (!success)
{
printf("failed connect: %s\n", sql.GetLastError());
return -1;
}
else
{
printf("connected: %d\n", sql.IsConnected());
}
}
如上,利用Raknet对MySQL的简单封装,写出来的连接操作就是上面黑体字那样的。注意倒数第二个参数:unix_socket,这个参数如果不需要,必须为NULL而不能是空字串"",空字串会导致连接失败。您先别急试,传NULL会导致MySQLInterface的底层崩溃,是这么崩的:
// DependentExtensions/MySQLInterface/MySQLInterface.cpp bool MySQLInterface::Connect(const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long clientflag) { if (IsConnected()) return false; _host=host; _user=user; _passwd=passwd; _db=db; _port=port; _unix_socket=unix_socket; _clientflag=clientflag; mySqlConnection = mysql_init(0); return mysql_real_connect (mySqlConnection, host, user, passwd, db, port, unix_socket, clientflag) != 0; }
//其中,这些下划线开头的成员的类型为: // Copy of connection parameters RakNet::RakString _host; RakNet::RakString _user; RakNet::RakString _passwd; RakNet::RakString _db; unsigned int _port; RakNet::RakString _unix_socket; unsigned long _clientflag;
另外,在下载Patcher的时候,调用的是:
//AutopatcherMySQLRpository.cpp 函数AutopatcherMySQLRepository::GetFilePart的片段: if (filePartConnection==0) { filePartConnection = mysql_init(0); mysql_real_connect(filePartConnection, _host, _user, _passwd, _db, _port, _unix_socket, _clientflag);一来,上面说了这个_unix_socket不是NULL,会导致连不上,而且没有判断是否成功。非常难查。
二来,发现了吗,RakString传参时可以直接当作C字符串来用,这个设计值得学习。如果像我一样觉得不爽,就用RakString的C_String()方法转换成正确的类型。
总之是个很讨厌的问题。而且还不是很好改。我最大的收获是通过这个BUG把Raknet源码好好跟了下 :)