视频播放如果只有一台视频服务器,当访问用户过多时,服务器将承受不了负载。
所以我们需要在视频服务器下面增加边缘服务器,下面以视频服务器加三台边缘服务器为例。
网络环境图:
1. 用户可通过PC机或手机访问网站。
2. 网站将用户请求转向到负载较小的边缘服务器。
3. 边缘服务器接收到用户请求,先在本地检查用户请求文件是否存在。
4. 如果存在则直接返回本地文件进行播放。
5. 如果不存在则将用户请求转向到视频服务器,并将该视频文件下载到本地。
6. 当用户请求边缘服务器上视频文件,将更新文件最后修改时间,最后修改时间超过一定天数则将该文件删除。
根据以上介绍我们应该对cdn有了一些了解,下面来看看代码方面怎么实现:
第一步先编写一个用于检查本地文件是否存在的IModule,该IModule存在以下文件:
配置文件:Config.xml
文件检查IModule:FileCheckModule.cs
文件检查配置获取:FileCheckConfig.cs
待下载文件信息添加:WaitDownFileTxtManage.cs
这里将待下载文件信息记录在txt文档里,大家在做的时候可以用一个Access数据库实现。
在部署该IModule的时候,需要将IIS处理程序映射中的StaticFile删除
然后添加新的脚本映射
可执行文件路径为
C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
这样的话,IModule便部署完成了,IModule接收到用户请求后先会在配置文件配置的本地文件路径中查找视频文件,如果找到文件则会转向到本地IIS中部署的另外一个文件站点;如果未找到文件则将请求转向到视频服务器。
第二步我们需要编写一个文件下载服务,该服务存在以下文件:
配置文件:App.config
下载文件服务,需在服务中添加一个时间控件:FileDown.cs
partial class FileDown : ServiceBase { //保存下载文件 Hashtable htDowFile = new Hashtable(); //下载文件数 int queueCount = Convert.ToInt32(ConfigurationManager.AppSettings["QueueCount"]); //当前下载文件数 int downCount = 0; public FileDown() { InitializeComponent(); } protected override void OnStart(string[] args) { // TODO: 在此处添加代码以启动服务。 fileDownTimer.Interval = 10000; fileDownTimer.Start(); //记录服务运行日志 Logger.LogDebug("FileDown", "OnStart", "文件下载服务开始运行。", null); } protected override void OnStop() { // TODO: 在此处添加代码以执行停止服务所需的关闭操作。 fileDownTimer.Stop(); //记录服务运行日志 Logger.LogDebug("FileDown", "OnStop", "文件下载服务停止运行。", null); } /// <summary> /// 时间控件处理事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void fileDownTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //记录文件下载日志 Logger.LogDebug("FileDown", "fileDownTimer_Elapsed", "开始一轮新的文件下载。", null); fileDownTimer.Stop(); WaitDownFileTxtManage myWaitDownFileXmlManage = new WaitDownFileTxtManage(); FileDownCommon myFileDownCommon = new FileDownCommon(); //从配置文件内获取txt文件路径 string txtPath = ConfigurationManager.AppSettings["txtPath"].ToString(); //循环下载所有文件 using (StreamReader sr = new StreamReader(txtPath)) { String line; while ((line = sr.ReadLine()) != null) { string[] fileElement = line.Split(';'); string downFileSavePath = fileElement[1] + ".downing"; if (!File.Exists(downFileSavePath)) { if (downCount <= queueCount) { downCount++; ThreadPool.QueueUserWorkItem(DownFile, line); } } } } //记录文件下载日志 Logger.LogDebug("FileDown", "fileDownTimer_Elapsed", "结束一轮新的文件下载。", null); Double interval = Convert.ToDouble(ConfigurationManager.AppSettings["Interval"].ToString()); fileDownTimer.Interval = interval * 60 * 1000; fileDownTimer.Start(); } /// <summary> /// 下载文件方法 /// </summary> /// <param name="downFile">下载文件</param> private void DownFile(object downFile) { WaitDownFileTxtManage myWaitDownFileTxtManage = new WaitDownFileTxtManage(); string[] fileElement = downFile.ToString().Split(';'); string fileName = fileElement[0]; string downFileSavePath = fileElement[1] + ".downing"; string trueFilePath = fileElement[1]; string fileDownPath = fileElement[2]; string pathNoFile = downFileSavePath.Substring(0, downFileSavePath.LastIndexOf("\\")); //检查保存路径是否存在 if (!Directory.Exists(pathNoFile)) { Directory.CreateDirectory(pathNoFile); } //记录文件下载日志 Logger.LogDebug("FileDownCommon", "DownFile", "\"" + fileDownPath + "\"文件开始下载。", null); //打开上次下载的文件或新建文件 long lStartPos = 0; System.IO.FileStream fs; if (System.IO.File.Exists(downFileSavePath)) { fs = System.IO.File.OpenWrite(downFileSavePath); lStartPos = fs.Length; fs.Seek(lStartPos, System.IO.SeekOrigin.Current); //移动文件流中的当前指针 } else { fs = new System.IO.FileStream(downFileSavePath, System.IO.FileMode.Create); lStartPos = 0; } //打开网络连接 try { System.Net.WebRequest webRequest = System.Net.WebRequest.Create(fileDownPath); webRequest.Timeout = 10000; System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)webRequest; System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); //System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(fileDownPath); //请求正常 if (response.StatusCode == System.Net.HttpStatusCode.OK) { if (lStartPos > 0) request.AddRange((int)lStartPos); //设置Range值 //向服务器请求,获得服务器回应数据流 System.IO.Stream ns = response.GetResponseStream(); byte[] nbytes = new byte[10240]; int nReadSize = 0; nReadSize = ns.Read(nbytes, 0, 10240); while (nReadSize > 0) { fs.Write(nbytes, 0, nReadSize); nReadSize = ns.Read(nbytes, 0, 10240); } fs.Close(); ns.Close(); File.Move(downFileSavePath, trueFilePath); //删除下载完成的文件 myWaitDownFileTxtManage.DeleteDownFile(fileName, trueFilePath, fileDownPath); downCount--; //记录文件下载日志 Logger.LogDebug("FileDownCommon", "DownFile", "\"" + fileDownPath + "\"文件下载完成。", null); } //文件未找到 else if (response.StatusCode == System.Net.HttpStatusCode.NotFound) { //删除不存在的文件 myWaitDownFileTxtManage.DeleteDownFile(fileName, trueFilePath, fileDownPath); downCount--; fs.Close(); Logger.LogDebug("FileDownCommon", "DownFile", "\"" + fileDownPath + "\"文件在服务器上不存在。", null); } } catch (FileNotFoundException fileEx) { fs.Close(); downCount--; //删除不存在的文件 myWaitDownFileTxtManage.DeleteDownFile(fileName, trueFilePath, fileDownPath); //记录异常日志 Logger.LogError("FileDownCommon", "DownFile", AppError.EROR, 0, fileEx, "\"" + fileDownPath + "\"文件在服务器上不存在。", null); } catch (Exception ex) { fs.Close(); downCount--; //记录异常日志 Logger.LogError("FileDownCommon", "DownFile", AppError.EROR, 0, ex, "下载文件\"" + fileDownPath + "\"过程中出现错误:" + ex.ToString(), null); } } }
待下载文件读取:WaitDownFileTxtManage.cs
通过以上几步便完成了一个简单的CDN视频文件内容分发网络。
大家在实现的时候还需要编写一个定时删除边缘服务器上过期文件的服务,该服务比较简单,这里便不做说明了。
希望我的文章对大家有帮助!
原文链接:https://www.cnblogs.com/fanmenglife/archive/2009/07/16/1524765.html
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/1569