緣由
本人從事游戲開發很多年一直都是游戲服務器端開發。
因為個人原因吧,一直在小型公司,或者叫創業型團隊工作吧。這樣的環境下不得不逼迫我需要什么都會,什么做。
但是自我感覺好像什么都不精通。。。。。
好了好像偏題了!
回歸正題
現在公司是做手游開發,java服務器 + U3D做客戶端的mmo手游,仿魔獸世界!
做軟件的都知道一個蛋疼的事情,那就是線上Bug。但是做服務的人更清楚另一個蛋疼的事情,就是在線更新,不停服更新。
知道的人,想想都蛋疼,當然不知道的,那就只能自己想象了。

線上經常出問題大家都是能理解的。bug肯定是有的。做服務的同僚應該都知道,不到維護的時間是不能停止服務區更新的除非是非常重大的bug。
這里面游戲服務器更為嚴格,因為你無故維護,維護一次可能就會流失一批玩家。所以這一直是一個梗。
本人經過三個星期的研究和測試,最終發現一個可以解決這種一出現bug,卻能在線更新,且不影響性能的觸發方式。

通過這樣一個方式,主程序,加數據庫,通過腳本實現邏輯模塊;
這樣就有一個腳本的實現形式,腳本如果實現的不好,那么性能消耗就很大了。
我的做法是把邏輯部分的方法抽象出來。放到腳本去實現。通過腳本把實現腳本邏輯代碼在注冊會邏輯模塊。
這樣的做法能保證我們有邏輯模塊有bug的時候及時的修改邏輯,再次注冊腳本已到達熱更新效果。保證服務器運行的穩定性。
我們開始吧。
首先我要說一下我這里使用的是C#語言作為講解。java也是一樣的道理。
不在贅述,如果需要代碼實現的可以留言!
這里可能牽涉到我之前的一些文章包含的類容,比如腳本加載器,日志模塊,http監聽模塊。
我們先創建一個控制台項目叫TestApp
在新建一個類庫項目 TestApp.Scripts

基本工作已經完成了。
接下來,我們在TestApp下面新建一個類IMainManager
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 8 /** 9 * 10 * @author 失足程序員 11 * @Blog http://www.cnblogs.com/ty408/ 12 * @mail 492794628@qq.com 13 * @phone 13882122019 14 * 15 */ 16 namespace TestApp 17 { 18 /// <summary> 19 /// 20 /// </summary> 21 public interface IMainManagerScript 22 { 23 24 void Test(); 25 26 } 27 }
我們在TestApp下面新建一個類MainManager
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 8 /** 9 * 10 * @author 失足程序員 11 * @Blog http://www.cnblogs.com/ty408/ 12 * @mail 492794628@qq.com 13 * @phone 13882122019 14 * 15 */ 16 namespace TestApp 17 { 18 /// <summary> 19 /// 20 /// </summary> 21 public class MainManager : IMainManagerScript 22 { 23 24 public static MainManager instance = new MainManager(); 25 26 public static MainManager GetInstance() 27 { 28 return instance; 29 } 30 31 public IMainManagerScript IScript; 32 33 public void Test() 34 { 35 IScript.Test(); 36 } 37 38 } 39 }
接下來我們在TestApp.Scripts 新建一個文件
1 using Net.Sz.Framework.Log; 2 using Net.Sz.Framework.Script; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 10 /** 11 * 12 * @author 失足程序員 13 * @Blog http://www.cnblogs.com/ty408/ 14 * @mail 492794628@qq.com 15 * @phone 13882122019 16 * 17 */ 18 namespace TestApp.Scripts 19 { 20 /// <summary> 21 /// 22 /// </summary> 23 public class MainManagerScript : BaseScript, IMainManagerScript 24 { 25 26 public void Test() 27 { 28 Logger.Info("我是test"); 29 } 30 31 public override void InitScript() 32 { 33 MainManager.GetInstance().IScript = this; 34 Logger.Info("MainManagerScripttest InitScript"); 35 } 36 37 } 38 }
1 using Net.Sz.Framework.Log; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace TestApp 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 //Logger.LOGCONSOLE = true;//不在控制台打印信息 15 //Logger.LOGLEVEL = Logger.ENUM_LOGLEVEL.INFO;//不顯示debug消息 16 Logger.Info("==================Start============================"); 17 18 Net.Sz.Framework.Script.ScriptManager.GetInstance().LoadCSharpFile(new string[] { "../../../TestApp.Scripts/" }); 19 20 MainManager.GetInstance().Test(); 21 22 Logger.Info("==================End============================"); 23 Console.ReadLine(); 24 } 25 } 26 }
我們先嘗試運行一次

也許上面的打印太亂,我們看看簡潔版本的

上面我們看樣看出來,功能是沒有問題的。
如果你稍微注意了,或者看過我之前的文章的話,會發現我的這個腳本沒有實現IBaseScript接口,而只繼承了BaseScript抽象類。
因為這樣的腳本不需要放到腳本存儲器里面,只需要執行init函數,把腳本自身反注冊到主程序函數體里面!
現在就是牽涉更新的事情。
更新有一個問題,當服務一旦部署后需要更新那就是的再次執行加載腳本方法。如果你使用windows服務運行的,更新勢必是一個問題。
這里我只介紹一種方式,http監聽方式。
要開啟http監聽方式,需要一個Net.Sz.Framework.Netty.Http.IHttpHandler的實現類
1 using Net.Sz.Framework.Log; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 9 /** 10 * 11 * @author 失足程序員 12 * @Blog http://www.cnblogs.com/ty408/ 13 * @mail 492794628@qq.com 14 * @phone 13882122019 15 * 16 */ 17 namespace TestApp 18 { 19 /// <summary> 20 /// 21 /// </summary> 22 public class ReloadScriptHandler : Net.Sz.Framework.Netty.Http.IHttpHandler 23 { 24 public void Action(Net.Sz.Framework.Netty.Http.HttpSession session, string method, string bindpath, Dictionary<string, string> parms) 25 { 26 Logger.Info("收到請求"); 27 28 Net.Sz.Framework.Script.ScriptManager.GetInstance().LoadCSharpFile(new string[] { "../../../TestApp.Scripts/" }); 29 MainManager.GetInstance().Test(); 30 31 session.writeSuccess(); 32 session.AddBodyLine("OK"); 33 session.WriteFlush(); 34 } 35 } 36 }
接下來我們在主函數加入下面代碼
Dictionary<string, Net.Sz.Framework.Netty.Http.IHttpHandler> handlers = new Dictionary<string, IHttpHandler>(); handlers.Add("ReloadScript", new ReloadScriptHandler());//開啟對http監聽,監聽模塊為 ReloadScript Net.Sz.Framework.Netty.NettyPool.GetInstance().AddHttpBind("127.0.0.1", 9527, handlers);
運行起來,看看,

可以看出,開啟了http監聽,reloadscript
然后我們修改一下MainManagerScript文件的Test方法
public void Test() { Logger.Info("我是test 修改過的版本"); }
在瀏覽器輸入:http://127.0.0.1:9527/reloadscript

運行時成功的。這樣的架構方式,很適合的是游戲開發,某些功能塊很容易出bug,如果用腳本存儲器訪問比較耗費性能。
這樣反向注冊功能塊腳本到功能塊,既能實現bug的熱更新,也不會影響性能消耗。
如果有疑問可以留言哦。如果你覺得這純粹是扯淡,也歡迎留言。
不要問我,邏輯部分都是源碼方服務器上安全嗎?
難道你打包就安全了?
反編譯,脫殼反混淆的工具一大堆。

上面是C#版本的,如果想要源碼,
或者是java源碼的,可以留言哦~!
