首页 > 代码库 > WinForms 小型HTML服务器

WinForms 小型HTML服务器

 

 最近教学,使用到了Apache和IIS,闲着无聊,有种想自己写个小服务器的冲动。

 

 在网上找了半天的资料,最后终于搞定了,测试可以访问。效果图如下:

 

 因为只是处理简单的请求,然后返回请求的页面,所以没有涉及到其他高级语言(php jsp aspx...)的处理。不过还是有点意思的哈,不说了,进入正题:

 

 开发工具:Visual Studio 2013

 开发环境:.NET Framework 2.0

 

关键源码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.IO;  4 using System.Text; 5  6 namespace Guying.Project.MiniServer 7 { 8     public class INIHelper 9     {10         private StreamReader sr;11         private string[] strs = new string[255];//该数值也限定了INI文件最多不能超过255行12         private int LinesOfTxt = 0;13         //private string FileName;14 15         public INIHelper(string iniFileName)16         {17             //FileName = iniFileName;18             if (!File.Exists(iniFileName))19             {20                 File.CreateText(iniFileName);21             }22             sr = new StreamReader((System.IO.Stream)File.OpenRead(iniFileName), Encoding.Default);23             //Console.WriteLine("Reading ini file: {0}",iniFileName);24             while (sr.Peek() > -1)25             {26                 strs[LinesOfTxt] = sr.ReadLine();27                 //把空行和以“#”或";"开头的注释行去掉28                 if (!strs[LinesOfTxt].StartsWith("#") && !strs[LinesOfTxt].StartsWith(";") && (strs[LinesOfTxt] != "")) LinesOfTxt++;29             }30             sr.Close();31         }32 33         /// <summary>34         /// 通过给定的value获得INI文件中对应项的值35         /// </summary>36         public string ValueOf(string cvalue)37         {38             string retn = "";39             int i = 0, index;40 41             while (i < LinesOfTxt)42             {43                 index = strs[i].IndexOf(cvalue + "=", 0, strs[i].Length);44                 if (index >= 0)45                 {46                     retn = strs[i].Substring(index + cvalue.Length + 1);47                     break;48                 }49                 i++;50             }51             return retn;52         }53 54     }55 }
读写INI配置文件的辅助类

 

这个辅助类是针对这个程序自己编写的,只有简单的读取和写入。

更多功能的ini通用辅助类,就像是DBHelper一样,网上有整套的代码、例如在此分享一个:

  1 using System;  2 using System.Collections.Generic;   3 using System.Runtime.InteropServices;  4 using System.Text;  5 using System.IO;  6 using System.Windows.Forms;  7 using System.Diagnostics;  8   9 namespace Guying.Project.MiniServer 10 { 11     /// <summary> 12     /// INI文件辅助类 13     /// </summary> 14     public class INIHelper_API 15     { 16  17         #region 声明读写INI文件的API函数 18         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileIntA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 19         private static extern int GetPrivateProfileInt(string lpApplicationName, string lpKeyName, int nDefault, string lpFileName); 20  21         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileSectionsNamesA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 22         private static extern int GetPrivateProfileSectionsNames(byte[] lpszReturnBuffer, int nSize, string lpFileName); 23  24         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStringA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 25         private static extern int GetPrivateProfileString(string lpApplicationName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName); 26  27         [DllImport("KERNEL32")] 28         private static extern int GetPrivateProfileString(string lpAppName, string lpszKey, string lpString, Byte[] lpStruct, int uSizeStruct, string lpFileName); 29  30         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStructA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 31         private static extern int GetPrivateProfileStruct(string lpszSections, string lpszKey, byte[] lpStruct, int uSizeStruct, string szFile); 32  33         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileSectionsA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 34         private static extern int WritePrivateProfileSections(string lpAppName, string lpString, string lpFileName); 35  36         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileStringA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 37         private static extern int WritePrivateProfileString(string lpApplicationName, string lpKeyName, string lpString, string lpFileName); 38  39         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileStructA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] 40         private static extern int WritePrivateProfileStruct(string lpszSections, string lpszKey, byte[] lpStruct, int uSizeStruct, string szFile); 41         #endregion 42  43         private string _INIFilePath = Environment.CurrentDirectory + "\\Configs\\{0}.ls.ini"; 44  45         #region 属性 46         private string _FilePath; 47         public string FilePath { get { return _FilePath; } set { _FilePath = value; } } 48  49         private string _ErrorMessage; 50         public string ErrorMessage { get { return _ErrorMessage; } set { _ErrorMessage = value; } } 51         #endregion 52  53         #region 构造函数 54         /// <summary> 55         /// 无参构造函数 56         /// </summary> 57         public INIHelper_API() { } 58         /// <summary> 59         /// 带参构造函数 60         /// </summary> 61         /// <param name="_iniFilePath">INI文件的绝对路径</param> 62         public INIHelper_API(string _iniFileName) 63         { 64             if (File.Exists(string.Format(_INIFilePath, _iniFileName))) 65             { 66                 this.FilePath = string.Format(_INIFilePath, _iniFileName); 67             } 68             else 69             { 70                 this.ErrorMessage = "系统配置文件不存在!"; 71  72                 this.FilePath = string.Format(_INIFilePath, _iniFileName); 73                 File.Create(this.FilePath); // 创建配置文件 74             } 75         } 76         #endregion 77  78         #region 将指定的值写入INI文件 79         /// <summary> 80         /// 将指定的值写入INI文件 81         /// </summary> 82         /// <param name="_sectionName">段落节点,格式[]</param> 83         /// <param name="_key"></param> 84         /// <param name="_value"></param> 85         public void WriteValue(string _sectionName, string _key, string _value) 86         { 87             // 如果当前指定的配置文件路径为空,即不存在 88             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath)) 89             { 90                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name); 91  92                 File.Create(this.FilePath); // 创建配置文件 93             } 94  95             WritePrivateProfileString(_sectionName, _key, _value, this.FilePath); 96         } 97         #endregion 98  99         #region 读取INI配置文件信息100         /// <summary>101         /// 读取INI配置文件信息102         /// </summary>103         /// <param name="_sectionName">段落节点,格式[]</param>104         /// <param name="_key">键名称</param>105         /// <returns>返回目标值</returns>106         public string ReadValue(string _sectionName, string _key)107         {108             // 如果当前指定的配置文件路径为空,即不存在109             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath))110             {111                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name);112 113                 File.Create(this.FilePath); // 创建配置文件114             }115 116             StringBuilder result = new StringBuilder(255);117             GetPrivateProfileString(_sectionName, _key, "", result, 255, this.FilePath);118             return result.ToString();119         }120         #endregion121 122         #region 读取INI配置文件123         /// <summary>124         /// 读取INI配置文件125         /// </summary>126         /// <param name="_sectionName">段落节点,格式[]</param>127         /// <param name="_key">键名称</param>128         /// <returns>返回byte类型的section组或键值组</returns>129         public byte[] ReadValues(string _sectionName, string _key)130         {131             byte[] result = new byte[255];132 133             // 如果当前指定的配置文件路径为空,即不存在134             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath))135             {136                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name);137 138                 File.Create(this.FilePath); // 创建配置文件139             }140 141             GetPrivateProfileString(_sectionName, _key, "", result, 255, this.FilePath);142             return result;143         }144         #endregion145     }146 }
网上其他的INI通用辅助类

 

其次就是程序运行需要的公用数据和方法:

 1 using System; 2 using System.Collections.Generic; 3 using System.IO;  4 using System.Text; 5 using System.Windows.Forms; 6  7 namespace Guying.Project.MiniServer 8 { 9     /// <summary>10     /// 提供系统运行时所需的公用数据和方法。11     /// 该类中的数据成员会被多个线程并发访问,12     /// 因此要求数据成员为静态的,并且仅在类的初始化时确定,13     /// 在其他函数或过程中对数据成员赋值是不安全的。14     /// </summary>15     public class ServerInfo16     {17 18         private static INIHelper _INIHelper = new INIHelper("httpsrv.ini");19 20         //private static string cgi=_INIHelper.ValueOf("cgi");21         private static string WWW_ROOT = _INIHelper.ValueOf("wwwroot");22         private static string NO_PAGE = _INIHelper.ValueOf("nopage");23         private static string DEFAULT_PAGE = _INIHelper.ValueOf("defaultpage");24         private static string WRONG_REQUEST_PAGE = _INIHelper.ValueOf("wrongrequest");25         private static string CACHE_DIR = _INIHelper.ValueOf("cachedir");26         private static string[] SPP_EXTS = _INIHelper.ValueOf("sppexts").Split(,);//get the knowed Server Process Page filename‘s extensions27         private static string[] APP_HANDLE_EXT = new string[SPP_EXTS.Length];//get the application name which handle such ext28 29         public ServerInfo()30         {31             FrmMain.GetInstance().ShowMessage("Loading Server Infomation...");32 33             for (int i = 0 ;i < sppexts.Length ; i++) AppHandleExt[i] = _INIHelper.ValueOf(sppexts[i]);34         }35         36         public string wwwroot37         {38             get 39             {40                 return WWW_ROOT;41             }42         }43 44         public string nopage45         {46             get 47             {48                 return NO_PAGE;49             }50         }51 52         public string defaultpage53         {54             get 55             {56                 return DEFAULT_PAGE;57             }58         }59 60         public string wrongrequestpage61         {62             get 63             {64                 return WRONG_REQUEST_PAGE;65             }66         }67 68         public string cacheDIR69         {70             get 71             {72                 return CACHE_DIR;73             }74         }75 76         public string[] sppexts77         {78             get 79             {80                 return SPP_EXTS;81             }82         }83 84         public string[] AppHandleExt85         {86             get 87             {88                 return APP_HANDLE_EXT;89             }90         }91     }92 }
程序运行需要的公用数据和方法

 

然后是读取配置文件,根据请求返回内容:

  1 using System;  2 using System.Collections.Generic;  3 using System.Diagnostics;  4 using System.IO;   5 using System.Net;  6 using System.Net.Sockets;  7 using System.Text;  8   9 namespace Guying.Project.MiniServer 10 { 11     /// <summary> 12     /// RequestProcessor 中的所有非 static 方法,字段都有可能并发执行 13     /// </summary> 14     public class RequestProcessor 15     { 16         private static INIHelper _INIHelper = new INIHelper("MIME.ini");//用于getMIMEType()中; 17  18         public static ServerInfo _ServerInfo;// = new SrvInfo();//can get from SrvMain 19  20         public Socket sockSendData;//Notice: get from ClientSocketThread.s 21         public string RequestID;//Notice: get from ClientSocketThread.currentThread.Name,now only for log 22  23         public RequestProcessor() 24         { 25             //Console.WriteLine("Loading \"RequestProcessor MODEL\" ...");             26         } 27  28         private void sendContent(FileStream fs, long start, long length) 29         { 30             try 31             { 32  33                 //报文头发送完毕,开始发送正文 34                 if (length == 0) length = fs.Length - start; 35                 const int SOCKETWINDOWSIZE = 8192; 36                 long r = SOCKETWINDOWSIZE; 37                 int rd = 0; 38                 Byte[] senddatas = new Byte[SOCKETWINDOWSIZE]; 39                 //MemoryStream sr = new MemoryStream(fs); 40                 fs.Seek(start, SeekOrigin.Begin); 41                 do 42                 { 43                     r = start + length - fs.Position; 44                     //fs.BeginRead(s,s,s,s,d) 以后使用的版本,用以提高读取的效率                 45                     if (r >= SOCKETWINDOWSIZE) rd = fs.Read(senddatas, 0, SOCKETWINDOWSIZE); 46                     else rd = fs.Read(senddatas, 0, (int)r); 47                     sockSendData.Send(senddatas, 0, rd, SocketFlags.None); 48                 } while (fs.Position != start + length); 49  50                 //if the fs is a temp FileStream then delete the file 51                 //for it created by server 52                 //other way, all files in cacheDIR will be deleted 53                 if (fs.Name.IndexOf(_ServerInfo.cacheDIR) >= 0) 54                 { 55                     string s = fs.Name; 56                     fs.Close(); 57                     File.Delete(s); 58                 } 59             } 60             catch (SocketException e) 61             { 62                 if (fs.Name.IndexOf(_ServerInfo.cacheDIR) >= 0) 63                 { 64                     string s = fs.Name; 65                     fs.Close(); 66                     File.Delete(s); 67                 } 68                 throw e; 69             } 70             catch (IOException e) 71             { 72                 throw e; 73             } 74         } 75  76         //ever used,now unused 77         private void sendContent(FileStream fs) 78         { 79             sendContent(fs, 0, 0); 80         } 81  82         private string getMIMEType(string filename) 83         { 84             string fname = filename, typename = "text/html"; 85             if ((filename != "/") && (filename.IndexOf("?") < 0)) 86             { 87                 int r = fname.LastIndexOf(.) + 1; 88                 fname = fname.Remove(0, r); 89                 if ((typename = _INIHelper.ValueOf(fname)) == "") typename = "application/" + fname; 90             } 91             return typename; 92         } 93  94         private FileStream PreProcessAndSendHeader(string filename, long start, long length) 95         { 96             Encoding coding = Encoding.Default; 97             Byte[] sendchars = new Byte[512]; 98             string strSend; 99             FileStream fs;100             try101             {102                 if (filename == "/") fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.defaultpage,103                                          FileMode.Open, FileAccess.Read, FileShare.ReadWrite);104 105                 else if (isCGIorSPP(filename)) fs = ProcessCGIorSPP(filename);//get a stream that the function returned106 107                 else fs = new FileStream(_ServerInfo.wwwroot + filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);108 109                 if (start == 0 && length == 0) strSend = "HTTP/1.1 200 OK";110                 else strSend = "HTTP/1.1 206 Partial Content";111                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());112                 sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);113 114             }115             catch (IOException)// FileNotFoundException)116             {117                 Console.WriteLine(FrmMain.strGMTDateTime() + " ERROR ID=[{0}]: {1} Request for file :\"{2}\" But NOT found", RequestID,118                     ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(), filename);119 120                 fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.nopage, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);121                 filename = _ServerInfo.nopage;122 123                 strSend = "HTTP/1.1 302 Found";124                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());125                 sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);126 127                 strSend = "Location: " + "http://" + ((IPEndPoint)sockSendData.LocalEndPoint).ToString() + "/" +128                     _ServerInfo.nopage; //maybe it‘s danger129                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());130                 sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);131             }132             catch (ArgumentException)//the request is WRONG133             {134                 Console.WriteLine(FrmMain.strGMTDateTime() + " ERROR ID=[{0}]: {1} send a WRONG request :\"{2}\" ", RequestID,135                     ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(), filename);136 137                 fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.wrongrequestpage, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);138                 filename = _ServerInfo.wrongrequestpage;139 140                 strSend = "HTTP/1.1 302 Found";141                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());142                 sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);143 144                 strSend = "Location: " + "http://" + ((IPEndPoint)sockSendData.LocalEndPoint).ToString() + "/" +145                     _ServerInfo.wrongrequestpage; //maybe it‘s danger146                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());147                 sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);148             }149 150 151             strSend = "Date: " + FrmMain.strGMTDateTime();152             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());153             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);154 155 156             strSend = "Server: httpsrv/1.0";157             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());158             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);159 160             strSend = "MIME-Version: 1.0";161             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());162             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);163 164             strSend = "Content-Type: " + getMIMEType(filename);165             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());166             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None); ;167 168             if (length == 0) length = fs.Length - start;169 170             strSend = "Content-Range: Bytes " + start.ToString() + "-" + (start + length - 1).ToString() + "/" + fs.Length.ToString();171             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());172             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);173 174             strSend = "Content-Length: " + length.ToString();175             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());176             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);177 178             //发送一个空行179             sendchars = coding.GetBytes(("\r\n").ToCharArray());180             sockSendData.Send(sendchars, 0, sendchars.Length, SocketFlags.None);181             return fs;182         }183 184         /// <summary>185         /// About returns:186         /// in HTTP 1.1 maybe the client need a Keep-Alive connection187         /// then it send header with a field "Connection: Keep-Alive"188         /// others who need NOT send header with a field "Connection: Closed"189         /// or have no this field in lower HTTP version190         /// Others:191         /// i dont check the client‘s HTTP version192         /// and assume it is HTTP 1.1193         /// </summary>194         /// <param name="RequestLines"></param>195         /// <returns>return true only if the client request a Keep-Alive connection</returns>196 197         public bool ParseRequestAndProcess(string[] RequestLines)198         {199             char[] sp = new Char[1] {   };200             string[] strs = RequestLines[0].Split(sp);201             if (strs[0] == "GET")202             {203                 long start = 0;204                 long length = 0;205                 foreach (string str in RequestLines)206                 {207                     if (str.StartsWith("Range:"))208                     {209                         string s = str.Substring(str.IndexOf("=") + 1);210                         string[] ss = s.Split(-);211                         start = Convert.ToInt64(ss[0]);212                         if (ss[1] != "") length = Convert.ToInt64(ss[1]) - start + 1;213 214                     }215                 }216                 if (isRequestSecurity(strs[1]))217                 {218                     sendContent(PreProcessAndSendHeader(strs[1], start, length), start, length);219                 }220                 else221                 {222                     sendContent(PreProcessAndSendHeader(_ServerInfo.wrongrequestpage, 0, 0), 0, 0);223                     Console.WriteLine(FrmMain.strGMTDateTime() + " WARNING ID=[{0}]: {1} send a WRONG request :\"{2}\" ", RequestID,224                         ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(),225                         strs[1]);226                 }227             }228             else229                 if (strs[0] == "HEAD")230                 {231                     if (isRequestSecurity(strs[1]))232                     {233                         PreProcessAndSendHeader(strs[1], 0, 0);234                     }235                 }236 237             foreach (string str in RequestLines)238             {239                 if (str.StartsWith("Connection:"))240                 {241                     string s = str.Substring(12);242                     if (s == "Keep-Alive") return true;243                 }244             }245             return false;246         }247 248         private bool isRequestSecurity(string strRequest)249         {250             if (strRequest.IndexOf("..") >= 0) return false;251             return true;252         }253 254         /// <summary>255         /// SPP is Server-end Process Page such as ASP php etc.256         /// </summary>257         private bool isCGIorSPP(string filename)258         {259             if (filename.IndexOf("?") >= 0) return true;260             string ext = filename.Substring(filename.LastIndexOf(".") + 1);261             for (int i = 0; i < _ServerInfo.sppexts.Length; i++)262             {263                 if ((ext == _ServerInfo.sppexts[i]) && (_ServerInfo.AppHandleExt[i] != ""))264                     return true;265             }266             return false;267         }268 269         /// <summary>270         /// return a FileStream get from CGI or SPP271         /// </summary>272         private FileStream ProcessCGIorSPP(string filename)273         {274             try275             {276                 string[] ss = new string[2];277                 if (filename.IndexOf("?") >= 0)278                 {279                     ss[0] = filename.Substring(0, filename.IndexOf("?"));280                     ss[1] = filename.Substring(filename.IndexOf("?") + 1);281                 }282                 else283                 {284                     ss[0] = filename; ss[1] = "";285                 }286                 while (ss[1].IndexOf("+") >= 0) ss[1] = ss[1].Replace("+", " ");287                 Process p = new Process();288                 string ext = "";289                 if (ss[0].LastIndexOf(".") >= 0) ext = ss[0].Substring(ss[0].LastIndexOf(".") + 1);290 291                 if ((ext != "") && (ext != "exe"))292                     for (int i = 0; i < _ServerInfo.sppexts.Length; i++)293                     {294                         if (ext == _ServerInfo.sppexts[i])295                         {296                             if (_ServerInfo.AppHandleExt[i] == "shell")297                             {298                                 p.StartInfo.FileName = _ServerInfo.wwwroot + ss[0].Remove(0, 1);299                                 p.StartInfo.Arguments = ss[1];300                             }301                             else302                             {303                                 p.StartInfo.FileName = _ServerInfo.AppHandleExt[i];304                                 p.StartInfo.Arguments = _ServerInfo.wwwroot + ss[0].Remove(0, 1) + " " + ss[1];305                             }306                             break;307                         }308                     }309                 else //ext == ""310                 {311                     p.StartInfo.FileName = _ServerInfo.wwwroot + ss[0].Remove(0, 1);312                     p.StartInfo.Arguments = ss[1];313                 }314 315                 p.StartInfo.UseShellExecute = false;316                 p.StartInfo.CreateNoWindow = true;317                 p.StartInfo.RedirectStandardOutput = true;318                 p.StartInfo.WorkingDirectory = p.StartInfo.FileName.Substring(0, p.StartInfo.FileName.LastIndexOf("/") + 1);319                 p.Start();320                 string s = p.StandardOutput.ReadToEnd();321                 if (!Directory.Exists(_ServerInfo.wwwroot + _ServerInfo.cacheDIR))322                     Directory.CreateDirectory(_ServerInfo.wwwroot + _ServerInfo.cacheDIR);323                 //ss[0] = ss[0].Substring(ss[0].LastIndexOf("/"));324                 FileStream fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.cacheDIR + RequestID + p.Id.ToString(),325                     FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);326                 fs.Write(Encoding.Default.GetBytes(s), 0, s.Length);327                 //p.WaitForExit();328                 return fs;329             }330             catch (System.Runtime.InteropServices.ExternalException)331             {332                 IOException e = new IOException();333                 throw e;334             }335             catch (System.SystemException)336             {337                 ArgumentException e = new ArgumentException();338                 throw e;339             }340 341         }342 343     }344 }
读取配置文件,根据请求返回内容

 

防止程序未响应,自定义多线程处理:

 1 using System; 2 using System.Collections.Generic;  3 using System.Net; 4 using System.Net.Sockets; 5 using System.Text; 6 using System.Threading; 7  8 namespace Guying.Project.MiniServer 9 {10     /// <summary>11     /// ClientSocketThread 的摘要说明。12     /// </summary>13     public class ClientSocketThread14     {15         public TcpListener tcpl;//Notice: get from SrvMain.tcpl16 17         private static Encoding ASCII = Encoding.ASCII;18         //private static int RequestID = 0;19 20         public void HandleThread()21         {22             string strClientIP = "";23             string strClientPort = "";24             string strLocalIP = "";25             string strLocalPort = "";26 27             Thread currentThread = Thread.CurrentThread;28 29             try30             {31                 // Accept will block until someone connects32                 Socket s = tcpl.AcceptSocket();33                 //RequestID++;34                 strLocalIP = ((IPEndPoint)s.LocalEndPoint).Address.ToString();35                 strLocalPort = ((IPEndPoint)s.LocalEndPoint).Port.ToString();36                 strClientIP = ((IPEndPoint)s.RemoteEndPoint).Address.ToString();37                 strClientPort = ((IPEndPoint)s.RemoteEndPoint).Port.ToString();38 39                 RequestProcessor aRequestProcessor = new RequestProcessor(); //Notice: 40                 aRequestProcessor.sockSendData = http://www.mamicode.com/s;//Notice: so that the processor can work41                 aRequestProcessor.RequestID = currentThread.Name;42 43                 const int BUFFERSIZE = 4096;//that‘s enough???44                 Byte[] readclientchar = new Byte[BUFFERSIZE];45                 char[] sps = new Char[2] { \r, \n };46                 string[] RequestLines = new string[32];47 48                 do49                 {50                     //use BUFFERSIZE contral the receive data size to avoid the BufferOverflow attack51                     int rc = s.Receive(readclientchar, 0, BUFFERSIZE, SocketFlags.None);52 53                     string strReceive = ASCII.GetString(readclientchar, 0, rc);54 55                     RequestLines = strReceive.Split(sps);56                     Console.WriteLine(FrmMain.strGMTDateTime() + " Request ID=[{0}] {1}->{2} :{3}",57                         currentThread.Name,58                         ((IPEndPoint)s.RemoteEndPoint).ToString(),59                         ((IPEndPoint)s.LocalEndPoint).ToString(),60                         RequestLines[0]);61 62                 } while (aRequestProcessor.ParseRequestAndProcess(RequestLines));63 64                 Console.WriteLine(FrmMain.strGMTDateTime() + " Closed ID=[{0}] {1}->{2} :Server Closed", currentThread.Name,65                     ((IPEndPoint)s.LocalEndPoint).ToString(), ((IPEndPoint)s.RemoteEndPoint).ToString());66                 s.Close();67             }68             catch (SocketException)69             {70                 Console.WriteLine(FrmMain.strGMTDateTime() + " Closed ID=[{0}] {1}:{2}->{3}:{4} :Client Closed", currentThread.Name,71                     strClientIP, strClientPort, strLocalIP, strLocalPort);72                 currentThread.Abort();73             }74         }75 76     }77 }
防止程序未响应,自定义多线程处理

 

最后,搭建测试窗体如下:

 

窗体调用实现方法的代码如下:

  1 using System;  2 using System.Collections.Generic;  3 using System.ComponentModel;  4 using System.Data;  5 using System.Diagnostics;  6 using System.Drawing;  7 using System.Net;  8 using System.Net.Sockets;  9 using System.Text; 10 using System.Text.RegularExpressions; 11 using System.Threading; 12 using System.Windows.Forms; 13  14 namespace Guying.Project.MiniServer 15 { 16     public partial class FrmMain : Form 17     { 18         private static FrmMain _FrmMain = null; 19         Thread _Thread = null; 20         Thread _myWorkerThread = null; 21  22         private FrmMain() 23         { 24             InitializeComponent(); 25         } 26  27         public static FrmMain GetInstance() 28         { 29             if (_FrmMain == null) 30             { 31                 _FrmMain = new FrmMain(); 32             } 33             return _FrmMain; 34         } 35  36         public void ShowMessage(string _messageStr) 37         { 38             this.listBox_Logs.Items.Add(_messageStr); 39         } 40  41         static public string strGMTDateTime() 42         { 43             DateTime GMTNow = DateTime.Now.ToUniversalTime(); 44             string month; 45             switch (GMTNow.Month) 46             { 47                 case 1: month = "Jan"; break; 48                 case 2: month = "Feb"; break; 49                 case 3: month = "Mar"; break; 50                 case 4: month = "Apr"; break; 51                 case 5: month = "May"; break; 52                 case 6: month = "Jun"; break; 53                 case 7: month = "Jul"; break; 54                 case 8: month = "Aug"; break; 55                 case 9: month = "Sep"; break; 56                 case 10: month = "Oct"; break; 57                 case 11: month = "Nov"; break; 58                 case 12: month = "Dec"; break; 59                 default: month = "Martian???"; break; 60             } 61             return 62                 GMTNow.DayOfWeek.ToString().Substring(0, 3) + ", " + GMTNow.Day.ToString() + " " + month + " " + GMTNow.Year.ToString() + " " + GMTNow.Hour.ToString() + ":" + GMTNow.Minute.ToString() + ":" + GMTNow.Second.ToString() + ":" + DateTime.Now.Millisecond.ToString() + " " + "GMT"; 63         } 64  65         private void btn_Start_Click(object sender, EventArgs e) 66         { 67             Start(); 68         } 69  70         void Start() 71         { 72             try 73             { 74                 ServerInfo _ServerInfo = new ServerInfo(); 75                 //i want to block the RequestProcessor when changing  _ServerInfo 76                 lock (typeof(RequestProcessor)) 77                 { 78                     RequestProcessor._ServerInfo = _ServerInfo; 79                 } 80  81                 ShowMessage("Starting NetWork listening..."); 82  83                 this.btn_Stop.Enabled = true; 84                 this.btn_Start.Enabled = false; 85  86                 TcpListener tcpListener; 87  88                 try 89                 { 90                     tcpListener = new TcpListener(IPAddress.Parse(this.cmb_IPAddresses.Text), int.Parse(this.txt_IPPoint.Text)); // listen on port 80 91                 } 92                 catch (Exception) 93                 { 94                     ShowMessage("Wrong argument:Using [[IP] (Port)] as the options"); 95                     return; 96                 } 97                 tcpListener.Start(); 98  99                 Console.WriteLine("Listening on {0}", ((IPEndPoint)tcpListener.LocalEndpoint).ToString());100                 Console.WriteLine("Server now waiting for clients to connect");101                 Console.WriteLine();102                 Console.WriteLine(strGMTDateTime() + " Server Start,Start logging");103                 //Console.WriteLine("Press Ctrl+c to Quit...");104 105                 int ThreadID = 0;106 107                 ThreadStart _ThreadStart = new ThreadStart(() =>108                 {109                     while (true)110                     {111                         while (!tcpListener.Pending())112                         {113                             Thread.Sleep(100);114                         }115 116                         ClientSocketThread myThreadHandler = new ClientSocketThread();117                         myThreadHandler.tcpl = tcpListener;//Notice: dont forget do this118                         ThreadStart myThreadStart = new ThreadStart(myThreadHandler.HandleThread);119                         _myWorkerThread = new Thread(myThreadStart);120                         _myWorkerThread.Name = (ThreadID++).ToString();121                         _myWorkerThread.Start();122                     }123                 });124 125                 _Thread = new Thread(_ThreadStart);126                 _Thread.Start();127 128             }129             catch (SocketException socketError)130             {131                 if (socketError.ErrorCode == 10048)132                 {133                     ShowMessage("Connection to this port failed.  There is another server is listening on this port.");134                 }135             }136             catch (FormatException)137             {138                 ShowMessage("invalid IP Address");139             }140             catch (Exception ex)141             {142                 ShowMessage("Ah O: " + ex.Message);143             }144         }145 146         private void FrmMain_Load(object sender, EventArgs e)147         {148             if (System.IO.File.Exists(Application.StartupPath + "\\Guying.ssk"))149             {150                 this.skinEngine.SkinFile = Application.StartupPath + "\\Guying.ssk";151                 this.skinEngine.SkinAllForm = true;152             }153 154             this.btn_Stop.Enabled = false;155             this.btn_Start.Enabled = true;156 157             this.cmb_IPAddresses.Items.Add("127.0.0.1");158 159             try160             {161                 this.cmb_IPAddresses.Items.Add(GetOutterIPAddress());162             }163             catch (Exception) { }164 165             IPAddress[] ipAddresses = Dns.GetHostAddresses(Environment.MachineName);166             foreach (IPAddress ip in ipAddresses)167             {168                 if (ip.AddressFamily == AddressFamily.InterNetwork)169                 {170                     this.cmb_IPAddresses.Items.Add(ip);171                 }172             }173         }174 175         private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)176         {177             Process.GetCurrentProcess().Kill();178         }179 180         public string GetOutterIPAddress()181         {182             string str = null;183             //这个负责抓IP的页。第一步先抓取这个html页的全部内容184             string url = "http://www.ikaka.com/ip/index.asp";185             WebClient wc = new WebClient();186             wc.Credentials = CredentialCache.DefaultCredentials;187             Byte[] pageData =http://www.mamicode.com/ wc.DownloadData(url);188             string MyUrl = System.Text.Encoding.UTF8.GetString(pageData);189             //正则找到页面中的IP部分,并输出。190             Regex regex = new Regex(@"(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))");191             foreach (Match m in regex.Matches(MyUrl))192             {193                 str = m.ToString();194             }195             return str;196 197         }198 199         private void btn_Stop_Click(object sender, EventArgs e)200         {201             _Thread.Abort();202             _myWorkerThread.Abort();203 204             this.btn_Start.Enabled = true;205             this.btn_Stop.Enabled = false;206         }207     }208 }
窗体调用实现方法的代码

 

最后,设置皮肤样式,呵呵,搞定:

 

 

在此,这个小程序就搞定了,希望有大神能帮忙加上php或者aspx等页面的支持。那就完美了。呵呵。

 

代码上面都有了,如果需要源码的请留言邮箱地址。

 

 

【来自:[LonelyShadow 博客] http://www.cnblogs.com/LonelyShadow】