先說結論,細節待補充。
目前發現兩處問題:
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_RESint 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.cppbool 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 parametersRakNet::RakString _host;RakNet::RakString _user;RakNet::RakString _passwd;RakNet::RakString _db;unsigned int _port;RakNet::RakString _unix_socket;unsigned long _clientflag;
也就是說,它們是RakString類型,無法表示NULL,而且賦值為NULL會導致Segmentation fault。
另外,在下載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源碼好好跟了下 :)