ASP.NET那點不為人知的事(三)

來源:互聯網
上載者:User
文章目錄
  •  開啟服務
  • 分析報文,處理請求 
  •   總結

有了以下的知識:

ASP.NET那點不為人知的事(一)

ASP.NET那點不為人知的事(二)

想必開發一個小型伺服器以不是問題了,功能補複雜,能夠響應用戶端瀏覽器的請求,並根據請求檔案的類型返迴響應的資訊,如能處理靜態頁面、圖片、樣式、指令碼、動態網頁面等。  回顧

由於用戶端和服務端的通訊是通過Socket通訊,且它們通訊的“語言”是基於Http1.1協議。根據這個線索,我們完全可以自己程式開發伺服器軟體,暫且叫他Melodies Server,當然這是一個很簡單的範例,和真正的伺服器還是有差距的,好,我們進入正題,首先需要瞭解以下幾個知識點:

  • 用戶端和服務端是由Socket進行通訊,在伺服器端需要有監聽請求的通訊端,他綁定在某個連接埠號碼上,如果發現有請求過來,socket.Accept()產生一個通訊端和用戶端進行通訊。
  • 用戶端發送的請求(報文)交給伺服器軟體分析,判斷是否為靜態頁面、圖片還是動態aspx檔案,若是靜態檔案能直接返回。
  • 處理動態網頁面稍稍麻煩,需要反射建立頁面類(原因詳見ASP.NET那點不為人知的事(二))
 開啟服務

 public partial class WebServerForm : Form    {        public WebServerForm()        {            InitializeComponent();            TextBox.CheckForIllegalCrossThreadCalls = false;        }        private Socket socketWatch;//負責監聽瀏覽器串連請求的通訊端             private Thread threadWatch;//負責迴圈調用Socket.Accept 監聽線程           private void btnStartServer_Click(object sender, EventArgs e)        {            socketWatch=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);            IPAddress address = IPAddress.Parse(txtIPAddress.Text.Trim());            IPEndPoint endPoint=new IPEndPoint(address,int.Parse(txtPort.Text.Trim()));            socketWatch.Bind(endPoint);            socketWatch.Listen(10);            threadWatch = new Thread(WatchConnect);            threadWatch.IsBackground = true;            threadWatch.Start();        }        private bool isWatch = true;        //Dictionary<>         void WatchConnect()        {            while (isWatch)            {                Socket socketConnection=socketWatch.Accept();                ShowMsg("瀏覽器:"+socketConnection.RemoteEndPoint.ToString()+",串連成功*********************");                ConnectionClient connectionClient = new ConnectionClient(socketConnection, ShowMsg);            }        }        void ShowMsg(string msg)        {            txtLog.AppendText(msg+"\r\n");        }            }
分析報文,處理請求 
  • 在非同步線程建立的與用戶端通訊的Socket,它的主要職責就是分析保文:
    /// <summary>    /// 與用戶端串連通訊類(包含一個與用戶端通訊的通訊端和通訊線程)    /// </summary>    public class ConnectionClient    {        private Socket socketMsg;//與用戶端通訊通訊端        private Thread threadMsg;//通訊線程        private DGShowMsg dgShowMsg;//負責向主表單文字框顯示訊息的委託        public ConnectionClient(Socket socket,DGShowMsg dgShowMsg)        {            this.socketMsg = socket;            this.dgShowMsg = dgShowMsg;            //負責啟動一個接受用戶端瀏覽器請求報文的線程            threadMsg = new Thread(ReceiveMsg);            threadMsg.IsBackground = true;            threadMsg.Start();        }        private bool isRec = true;        void ReceiveMsg()        {            while (isRec)            {                byte[] arrMsg=new byte[1024*1024*3];                //接受對應用戶端發送過來的請求報文                int length = socketMsg.Receive(arrMsg);                string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg, 0, length);                dgShowMsg(strMsg);                //處理報文                string[] arrStr = strMsg.Replace("\r\n", "韘").Split('韘');                string[] firstRow=arrStr[0].Split(' ');                string requestFile = firstRow[1];                ExcuteRequest(requestFile);//todo:長串連多少時間            }        }        private void ExcuteRequest(string requestFile)        {            //獲得被請求頁面的尾碼名            string fileExtension = System.IO.Path.GetExtension(requestFile);            if (!string.IsNullOrEmpty(fileExtension))            {                switch (fileExtension.ToLower())            {                    case ".html":                    case ".htm":                    case ".css":                    case ".js":                                       ExcuteStaticPage(requestFile,fileExtension);                    break;                    case ".jpg":                    ExcuteImg(requestFile,fileExtension);                    break;                    case ".aspx":                    ExcuteDymPage(requestFile,fileExtension);                    break;            }            }        }
  •   針對不同的請求執行不同的操作,其中靜態頁面、css、js、圖片處理操作一樣,都是屬性靜態檔案,直接返回位元組流:
/// <summary>        /// 處理靜態頁面,直接輸出        /// </summary>        private void ExcuteStaticPage(string requestPath,string fileExtension)        {            StringBuilder sb=new StringBuilder();            //獲得請求檔案的檔案夾的實體路徑            string dataDir = AppDomain.CurrentDomain.BaseDirectory;            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release\"))            {                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;            }            string phyPath = dataDir + requestPath;            //讀取靜態頁面內容            string fileContent = System.IO.File.ReadAllText(phyPath);            //獲得響應體位元組數組            byte[] fileArr = System.Text.Encoding.UTF8.GetBytes(fileContent);            //獲得響應報文頭:            string responseHeader = GetResponseHeader(fileArr.Length, fileExtension);            byte[] arrHead = System.Text.Encoding.UTF8.GetBytes(responseHeader);            //發送響應報文頭回瀏覽器            socketMsg.Send(arrHead);            //發送響應報文體回瀏覽器            //todo:sleep 1分鐘會怎樣            socketMsg.Send(fileArr);        }        /// <summary>        /// 處理圖片        /// </summary>        /// <param name="requestPath"></param>        /// <param name="extentionName"></param>        private void ExcuteImg(string requestPath, string extentionName)        {            //獲得請求檔案的檔案夾的實體路徑            string dataDir = AppDomain.CurrentDomain.BaseDirectory;            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release"))            {                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;            }            //獲得請求檔案的實體路徑(絕對路徑)            string phyPath = dataDir + requestPath;            int imgLength;            byte[] fileArr;            //讀取圖片內容            using (FileStream fs = new FileStream(phyPath, FileMode.Open))            {                fileArr = new byte[fs.Length];                imgLength = fs.Read(fileArr, 0, fileArr.Length);                //獲得響應報文頭                string responseHeader = GetResponseHeader(imgLength, extentionName);                byte[] arrHeader = System.Text.Encoding.UTF8.GetBytes(responseHeader);                socketMsg.Send(arrHeader);                socketMsg.Send(fileArr, imgLength, SocketFlags.None);            }        }        /// <summary>        /// 得到回應標頭資訊        /// </summary>        /// <param name="contentLength"></param>        /// <param name="fileExtentionName"></param>        /// <returns></returns>        private string GetResponseHeader(int contentLength,string fileExtentionName)        {            StringBuilder sbHeader=new StringBuilder();            sbHeader.Append("HTTP/1.1 200 OK\r\n");            sbHeader.Append("Content-Length: "+contentLength+"\r\n");            sbHeader.Append("Content-Type:" + GetResponseHeadContentType(fileExtentionName) + ";charset=utf-8\r\n\r\n");            return sbHeader.ToString();        }        /// <summary>        /// 根據尾碼名擷取響應保文中的內容類型        /// </summary>        /// <param name="fileExtentionName"></param>        /// <returns></returns>        private string GetResponseHeadContentType(string fileExtentionName)        {            switch (fileExtentionName.ToLower())            {                case ".html":                case ".htm":                case ".aspx":                    return "text/html";                    break;                case ".css":                    return "text/plain";                    break;                case ".js":                    return "text/javascript";                    break;                case ".jpg":                    return "image/JPEG";                case ".gif":                    return "image/GIF";                    break;                default:                    return "text/html";                    break;            }        }
  • 同樣,針對動態網頁面反射建立其頁面類,注意記得讓其實現IHttpHandler介面
  • 建立一個頁面類View
 public class View:IHttpHandler    {        public string ProcessRequest()        {            string dataDir = AppDomain.CurrentDomain.BaseDirectory;            //獲得模板實體路徑            if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release"))            {                dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;            }            string phyPath = dataDir + "/model.htm";            string modelContent=System.IO.File.ReadAllText(phyPath);            modelContent = modelContent.Replace("@Title", "動態網頁面").Replace("@Content", "反射建立頁面類");            return modelContent;        }    }
  • 反射View,調用其ProcessRequest方法執行服務端代碼
  /// <summary>        /// 反射建立動態網頁面對象        /// </summary>        /// <param name="requestFile"></param>        /// <param name="extentionName"></param>        private void ExcuteDymPage(string requestFile, string extentionName)        {            string pageClassName = System.IO.Path.GetFileNameWithoutExtension(requestFile);            string assemblyName = Assembly.GetExecutingAssembly().GetName().Name;            //獲得頁面類全名稱            pageClassName = assemblyName + "." + pageClassName;            //通過反射建立頁面類對象            object pageObj = Assembly.GetExecutingAssembly().CreateInstance(pageClassName);            IHttpHandler page = pageObj as IHttpHandler;            byte[] fileArr=null;            if (page!=null)            {                string strHtml=page.ProcessRequest();                fileArr= System.Text.Encoding.UTF8.GetBytes(strHtml);            }            //獲得響應報文頭            string responseHeader = GetResponseHeader(fileArr.Length, extentionName);            byte[] arrHeader = System.Text.Encoding.UTF8.GetBytes(responseHeader);            socketMsg.Send(arrHeader);            socketMsg.Send(fileArr);        }
  總結

至此,一個小型的伺服器軟體就構建好了,趕緊測試一下呵呵。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.