本篇是 Http 服务器系列博文的第十篇,对应项目是 LiteHttp,具体可访问 https://dreamyouxi.com/about#litehttp。

Unity 引擎中 C# 脚本的运行环境是 Mono 平台,而非微软的 .NET,Unity 引擎本身大部分由 C++ 编写。

在 LiteHttp 项目中,原本已支持 Lua 脚本来书写动态网页。这里引入 C# 脚本,目的是辅助 C++ 端的开发工作。

把 C# 当脚本语言来使用,相比 Lua 优势更多,底层依然基于 C++ 构建。

环境搭建

step1:去 Mono 官网下载 msi 安装包,x64 和 x86 分别对应 64 位和 32 位 exe。

step2:编写 C# 与 C++ 测试代码。

C++ 端示例:

C# 端示例:

C++ 运行结果:

在 LiteHttpSvr 中的初步应用:文件系统

将原本 C++ 端的文件读取与缓存逻辑迁移到 C# 实现。

C++ 端的修改:

C# 端实现:

using System;
                using System.Collections.Generic;
                using System.IO;
                
                namespace LiteHttpScript
                {
                    class CppEntry
                    {
                        static string CallMain(string file)
                        {
                            try
                            {
                                //System.Console.WriteLine("[C# Handle]:" + file);
                                return FileCache.Handle(file);
                            }
                            catch (Exception e)
                            {
                                System.Console.WriteLine("Err:" + e.Message);
                                return "";
                            }
                        }
                    }
                    public class FileCache
                    {
                        static FileCacheImpl impl = new FileCacheImpl();
                        public static string Handle(string file)
                        {
                            lock (impl)
                            {
                                return impl.GetFile(file);
                            }
                        }
                    };
                
                    //sample LRU file cache which limited by memory
                    public class FileCacheImpl
                    {
                        class FileData
                        {
                            public string key;
                            public string data;
                            public DateTime lastModifyUTCTime;
                        }
                
                        public string GetFile(string file)
                        {
                            LinkedListNode<FileData> ret = null;
                
                            if (_cache.TryGetValue(file, out ret))
                            {
                                //has find cache
                                _list.Remove(ret);
                                _list.AddFirst(ret);
                                //check file will update or not
                
                            }
                            else
                            {
                                //missing cache
                                try
                                {
                                    var data = new FileData();
                                    var info = new FileInfo(file);
                                    data.lastModifyUTCTime = info.LastWriteTimeUtc;
                                    data.data = File.ReadAllText(file);
                                    data.key = file;
                
                                    ret = new LinkedListNode<FileData>(data);
                
                                    _list.AddFirst(ret);
                                    _cache.Add(file, ret);
                
                                    _currentMemoryUseage += data.data.Length;
                                }
                                catch (Exception e)
                                {
                                    //file not exist
                                    return "";
                                }
                            }
                
                            while (_list.Count > 1 && _currentMemoryUseage >= MaxMenmoryCacheSize)
                            {
                                var tail = _list.Last;
                                _cache.Remove(tail.Value.Value.key);
                                _list.RemoveLast();
                                _currentMemoryUseage -= tail.Value.Value.data.Length;
                            }
                            //GC.Collect();
                            return ret.Value.data;
                        }
                
                
                        // private long MaxMenmoryCacheSize { get { return 104857600L; } }//最大缓存大小 100 MB
                        private long MaxMenmoryCacheSize { get { return 100L; } }//最大缓存大小 100 MB
                
                
                        //   private long MaxCacheFileNum { get { return 1024; } }//最大文件缓存数量
                
                        private long _currentMemoryUseage = 0;
                
                        private Dictionary<string, LinkedListNode<FileData>> _cache = new Dictionary<string, LinkedListNode<FileData>>();
                
                        private LinkedList<LinkedListNode<FileData>> _list = new LinkedList<LinkedListNode<FileData>>();
                    };
                
                }
                

输出结果:

关于脚本语言还可以具备的其他特性,比如热更新,C# 同样可以支持。