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

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

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

 开发工具:Visual Studio 2013

 开发环境:.NET Framework 2.0

关键源码如下:

 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;

 namespace Guying.Project.MiniServer
 {
     public class INIHelper
     {
         private StreamReader sr;
         ];//该数值也限定了INI文件最多不能超过255行
         ;
         //private string FileName;

         public INIHelper(string iniFileName)
         {
             //FileName = iniFileName;
             if (!File.Exists(iniFileName))
             {
                 File.CreateText(iniFileName);
             }
             sr = new StreamReader((System.IO.Stream)File.OpenRead(iniFileName), Encoding.Default);
             //Console.WriteLine("Reading ini file: {0}",iniFileName);
             )
             {
                 strs[LinesOfTxt] = sr.ReadLine();
                 //把空行和以“#”或";"开头的注释行去掉
                 if (!strs[LinesOfTxt].StartsWith("#") && !strs[LinesOfTxt].StartsWith(";") && (strs[LinesOfTxt] != "")) LinesOfTxt++;
             }
             sr.Close();
         }

         /// <summary>
         /// 通过给定的value获得INI文件中对应项的值
         /// </summary>
         public string ValueOf(string cvalue)
         {
             string retn = "";
             , index;

             while (i < LinesOfTxt)
             {
                 index = strs[i].IndexOf(cvalue + , strs[i].Length);
                 )
                 {
                     retn = strs[i].Substring(index + cvalue.Length + );
                     break;
                 }
                 i++;
             }
             return retn;
         }

     }
 }

读写INI配置文件的辅助类

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

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

 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.IO;
 using System.Windows.Forms;
 using System.Diagnostics;

 namespace Guying.Project.MiniServer
 {
     /// <summary>
     /// INI文件辅助类
     /// </summary>
     public class INIHelper_API
     {

         #region 声明读写INI文件的API函数
         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileIntA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int GetPrivateProfileInt(string lpApplicationName, string lpKeyName, int nDefault, string lpFileName);

         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileSectionsNamesA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int GetPrivateProfileSectionsNames(byte[] lpszReturnBuffer, int nSize, string lpFileName);

         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStringA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int GetPrivateProfileString(string lpApplicationName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, int nSize, string lpFileName);

         [DllImport("KERNEL32")]
         private static extern int GetPrivateProfileString(string lpAppName, string lpszKey, string lpString, Byte[] lpStruct, int uSizeStruct, string lpFileName);

         [DllImport("KERNEL32.DLL", EntryPoint = "GetPrivateProfileStructA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int GetPrivateProfileStruct(string lpszSections, string lpszKey, byte[] lpStruct, int uSizeStruct, string szFile);

         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileSectionsA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int WritePrivateProfileSections(string lpAppName, string lpString, string lpFileName);

         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileStringA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int WritePrivateProfileString(string lpApplicationName, string lpKeyName, string lpString, string lpFileName);

         [DllImport("KERNEL32.DLL", EntryPoint = "WritePrivateProfileStructA", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)]
         private static extern int WritePrivateProfileStruct(string lpszSections, string lpszKey, byte[] lpStruct, int uSizeStruct, string szFile);
         #endregion

         private string _INIFilePath = Environment.CurrentDirectory + "\\Configs\\{0}.ls.ini";

         #region 属性
         private string _FilePath;
         public string FilePath { get { return _FilePath; } set { _FilePath = value; } }

         private string _ErrorMessage;
         public string ErrorMessage { get { return _ErrorMessage; } set { _ErrorMessage = value; } }
         #endregion

         #region 构造函数
         /// <summary>
         /// 无参构造函数
         /// </summary>
         public INIHelper_API() { }
         /// <summary>
         /// 带参构造函数
         /// </summary>
         /// <param name="_iniFilePath">INI文件的绝对路径</param>
         public INIHelper_API(string _iniFileName)
         {
             if (File.Exists(string.Format(_INIFilePath, _iniFileName)))
             {
                 this.FilePath = string.Format(_INIFilePath, _iniFileName);
             }
             else
             {
                 this.ErrorMessage = "系统配置文件不存在!";

                 this.FilePath = string.Format(_INIFilePath, _iniFileName);
                 File.Create(this.FilePath); // 创建配置文件
             }
         }
         #endregion

         #region 将指定的值写入INI文件
         /// <summary>
         /// 将指定的值写入INI文件
         /// </summary>
         /// <param name="_sectionName">段落节点,格式[]</param>
         /// <param name="_key">键</param>
         /// <param name="_value">值</param>
         public void WriteValue(string _sectionName, string _key, string _value)
         {
             // 如果当前指定的配置文件路径为空,即不存在
             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath))
             {
                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name);

                 File.Create(this.FilePath); // 创建配置文件
             }

             WritePrivateProfileString(_sectionName, _key, _value, this.FilePath);
         }
         #endregion

         #region 读取INI配置文件信息
         /// <summary>
         /// 读取INI配置文件信息
         /// </summary>
         /// <param name="_sectionName">段落节点,格式[]</param>
         /// <param name="_key">键名称</param>
         /// <returns>返回目标值</returns>
         public string ReadValue(string _sectionName, string _key)
         {
             // 如果当前指定的配置文件路径为空,即不存在
             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath))
             {
                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name);

                 File.Create(this.FilePath); // 创建配置文件
             }

             StringBuilder result = );
             GetPrivateProfileString(_sectionName, _key, , this.FilePath);
             return result.ToString();
         }
         #endregion

         #region 读取INI配置文件
         /// <summary>
         /// 读取INI配置文件
         /// </summary>
         /// <param name="_sectionName">段落节点,格式[]</param>
         /// <param name="_key">键名称</param>
         /// <returns>返回byte类型的section组或键值组</returns>
         public byte[] ReadValues(string _sectionName, string _key)
         {
             ];

             // 如果当前指定的配置文件路径为空,即不存在
             if (this.FilePath == null || string.IsNullOrEmpty(this.FilePath.Trim()) || !File.Exists(this.FilePath))
             {
                 this.FilePath = string.Format(_INIFilePath, new FileInfo(Application.ExecutablePath).Name);

                 File.Create(this.FilePath); // 创建配置文件
             }

             GetPrivateProfileString(_sectionName, _key, , this.FilePath);
             return result;
         }
         #endregion
     }
 }

网上其他的INI通用辅助类

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

 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
 using System.Windows.Forms;

 namespace Guying.Project.MiniServer
 {
     /// <summary>
     /// 提供系统运行时所需的公用数据和方法。
     /// 该类中的数据成员会被多个线程并发访问,
     /// 因此要求数据成员为静态的,并且仅在类的初始化时确定,
     /// 在其他函数或过程中对数据成员赋值是不安全的。
     /// </summary>
     public class ServerInfo
     {

         private static INIHelper _INIHelper = new INIHelper("httpsrv.ini");

         //private static string cgi=_INIHelper.ValueOf("cgi");
         private static string WWW_ROOT = _INIHelper.ValueOf("wwwroot");
         private static string NO_PAGE = _INIHelper.ValueOf("nopage");
         private static string DEFAULT_PAGE = _INIHelper.ValueOf("defaultpage");
         private static string WRONG_REQUEST_PAGE = _INIHelper.ValueOf("wrongrequest");
         private static string CACHE_DIR = _INIHelper.ValueOf("cachedir");
         private static string[] SPP_EXTS = _INIHelper.ValueOf("sppexts").Split(',');//get the knowed Server Process Page filename's extensions
         private static string[] APP_HANDLE_EXT = new string[SPP_EXTS.Length];//get the application name which handle such ext

         public ServerInfo()
         {
             FrmMain.GetInstance().ShowMessage("Loading Server Infomation...");

              ;i < sppexts.Length ; i++) AppHandleExt[i] = _INIHelper.ValueOf(sppexts[i]);
         }

         public string wwwroot
         {
             get
             {
                 return WWW_ROOT;
             }
         }

         public string nopage
         {
             get
             {
                 return NO_PAGE;
             }
         }

         public string defaultpage
         {
             get
             {
                 return DEFAULT_PAGE;
             }
         }

         public string wrongrequestpage
         {
             get
             {
                 return WRONG_REQUEST_PAGE;
             }
         }

         public string cacheDIR
         {
             get
             {
                 return CACHE_DIR;
             }
         }

         public string[] sppexts
         {
             get
             {
                 return SPP_EXTS;
             }
         }

         public string[] AppHandleExt
         {
             get
             {
                 return APP_HANDLE_EXT;
             }
         }
     }
 }

程序运行需要的公用数据和方法

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

 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;

 namespace Guying.Project.MiniServer
 {
     /// <summary>
     /// RequestProcessor 中的所有非 static 方法,字段都有可能并发执行
     /// </summary>
     public class RequestProcessor
     {
         private static INIHelper _INIHelper = new INIHelper("MIME.ini");//用于getMIMEType()中;

         public static ServerInfo _ServerInfo;// = new SrvInfo();//can get from SrvMain

         public Socket sockSendData;//Notice: get from ClientSocketThread.s
         public string RequestID;//Notice: get from ClientSocketThread.currentThread.Name,now only for log

         public RequestProcessor()
         {
             //Console.WriteLine("Loading \"RequestProcessor MODEL\" ...");
         }

         private void sendContent(FileStream fs, long start, long length)
         {
             try
             {

                 //报文头发送完毕,开始发送正文
                 ) length = fs.Length - start;
                 ;
                 long r = SOCKETWINDOWSIZE;
                 ;
                 Byte[] senddatas = new Byte[SOCKETWINDOWSIZE];
                 //MemoryStream sr = new MemoryStream(fs);
                 fs.Seek(start, SeekOrigin.Begin);
                 do
                 {
                     r = start + length - fs.Position;
                     //fs.BeginRead(s,s,s,s,d) 以后使用的版本,用以提高读取的效率
                     , SOCKETWINDOWSIZE);
                     , (int)r);
                     sockSendData.Send(senddatas, , rd, SocketFlags.None);
                 } while (fs.Position != start + length);

                 //if the fs is a temp FileStream then delete the file
                 //for it created by server
                 //other way, all files in cacheDIR will be deleted
                 )
                 {
                     string s = fs.Name;
                     fs.Close();
                     File.Delete(s);
                 }
             }
             catch (SocketException e)
             {
                 )
                 {
                     string s = fs.Name;
                     fs.Close();
                     File.Delete(s);
                 }
                 throw e;
             }
             catch (IOException e)
             {
                 throw e;
             }
         }

         //ever used,now unused
         private void sendContent(FileStream fs)
         {
             sendContent(fs, , );
         }

         private string getMIMEType(string filename)
         {
             string fname = filename, typename = "text/html";
             ))
             {
                 ;
                 fname = fname.Remove(, r);
                 if ((typename = _INIHelper.ValueOf(fname)) == "") typename = "application/" + fname;
             }
             return typename;
         }

         private FileStream PreProcessAndSendHeader(string filename, long start, long length)
         {
             Encoding coding = Encoding.Default;
             Byte[] sendchars = ];
             string strSend;
             FileStream fs;
             try
             {
                 if (filename == "/") fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.defaultpage,
                                          FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                 else if (isCGIorSPP(filename)) fs = ProcessCGIorSPP(filename);//get a stream that the function returned

                 else fs = new FileStream(_ServerInfo.wwwroot + filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                  && length == ) strSend = "HTTP/1.1 200 OK";
                 else strSend = "HTTP/1.1 206 Partial Content";
                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
                 sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             }
             catch (IOException)// FileNotFoundException)
             {
                 Console.WriteLine(FrmMain.strGMTDateTime() + " ERROR ID=[{0}]: {1} Request for file :\"{2}\" But NOT found", RequestID,
                     ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(), filename);

                 fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.nopage, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                 filename = _ServerInfo.nopage;

                 strSend = "HTTP/1.1 302 Found";
                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
                 sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

                 strSend = "Location: " + "http://" + ((IPEndPoint)sockSendData.LocalEndPoint).ToString() + "/" +
                     _ServerInfo.nopage; //maybe it's danger
                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
                 sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);
             }
             catch (ArgumentException)//the request is WRONG
             {
                 Console.WriteLine(FrmMain.strGMTDateTime() + " ERROR ID=[{0}]: {1} send a WRONG request :\"{2}\" ", RequestID,
                     ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(), filename);

                 fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.wrongrequestpage, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                 filename = _ServerInfo.wrongrequestpage;

                 strSend = "HTTP/1.1 302 Found";
                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
                 sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

                 strSend = "Location: " + "http://" + ((IPEndPoint)sockSendData.LocalEndPoint).ToString() + "/" +
                     _ServerInfo.wrongrequestpage; //maybe it's danger
                 sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
                 sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);
             }

             strSend = "Date: " + FrmMain.strGMTDateTime();
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             strSend = "Server: httpsrv/1.0";
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             strSend = "MIME-Version: 1.0";
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             strSend = "Content-Type: " + getMIMEType(filename);
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None); ;

             ) length = fs.Length - start;

             strSend = ).ToString() + "/" + fs.Length.ToString();
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             strSend = "Content-Length: " + length.ToString();
             sendchars = coding.GetBytes((strSend + "\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);

             //发送一个空行
             sendchars = coding.GetBytes(("\r\n").ToCharArray());
             sockSendData.Send(sendchars, , sendchars.Length, SocketFlags.None);
             return fs;
         }

         /// <summary>
         /// About returns:
         /// in HTTP 1.1 maybe the client need a Keep-Alive connection
         /// then it send header with a field "Connection: Keep-Alive"
         /// others who need NOT send header with a field "Connection: Closed"
         /// or have no this field in lower HTTP version
         /// Others:
         /// i dont check the client's HTTP version
         /// and assume it is HTTP 1.1
         /// </summary>
         /// <param name="RequestLines"></param>
         /// <returns>return true only if the client request a Keep-Alive connection</returns>

         public bool ParseRequestAndProcess(string[] RequestLines)
         {
             ] { ' ' };
             ].Split(sp);
             ] == "GET")
             {
                 ;
                 ;
                 foreach (string str in RequestLines)
                 {
                     if (str.StartsWith("Range:"))
                     {
                         );
                         string[] ss = s.Split('-');
                         start = Convert.ToInt64(ss[]);
                         ] != ]) - start + ;

                     }
                 }
                 ]))
                 {
                     sendContent(PreProcessAndSendHeader(strs[], start, length), start, length);
                 }
                 else
                 {
                     sendContent(PreProcessAndSendHeader(_ServerInfo.wrongrequestpage, , ), , );
                     Console.WriteLine(FrmMain.strGMTDateTime() + " WARNING ID=[{0}]: {1} send a WRONG request :\"{2}\" ", RequestID,
                         ((IPEndPoint)sockSendData.RemoteEndPoint).ToString(),
                         strs[]);
                 }
             }
             else
                 ] == "HEAD")
                 {
                     ]))
                     {
                         PreProcessAndSendHeader(strs[], , );
                     }
                 }

             foreach (string str in RequestLines)
             {
                 if (str.StartsWith("Connection:"))
                 {
                     );
                     if (s == "Keep-Alive") return true;
                 }
             }
             return false;
         }

         private bool isRequestSecurity(string strRequest)
         {
             ) return false;
             return true;
         }

         /// <summary>
         /// SPP is Server-end Process Page such as ASP php etc.
         /// </summary>
         private bool isCGIorSPP(string filename)
         {
             ) return true;
             );
             ; i < _ServerInfo.sppexts.Length; i++)
             {
                 if ((ext == _ServerInfo.sppexts[i]) && (_ServerInfo.AppHandleExt[i] != ""))
                     return true;
             }
             return false;
         }

         /// <summary>
         /// return a FileStream get from CGI or SPP
         /// </summary>
         private FileStream ProcessCGIorSPP(string filename)
         {
             try
             {
                 ];
                 )
                 {
                     ss[] = filename.Substring(, filename.IndexOf("?"));
                     ss[] = filename.Substring(filename.IndexOf();
                 }
                 else
                 {
                     ss[] = filename; ss[] = "";
                 }
                 ].IndexOf() ss[] = ss[].Replace("+", " ");
                 Process p = new Process();
                 string ext = "";
                 ].LastIndexOf() ext = ss[].Substring(ss[].LastIndexOf();

                 if ((ext != "") && (ext != "exe"))
                     ; i < _ServerInfo.sppexts.Length; i++)
                     {
                         if (ext == _ServerInfo.sppexts[i])
                         {
                             if (_ServerInfo.AppHandleExt[i] == "shell")
                             {
                                 p.StartInfo.FileName = _ServerInfo.wwwroot + ss[].Remove(, );
                                 p.StartInfo.Arguments = ss[];
                             }
                             else
                             {
                                 p.StartInfo.FileName = _ServerInfo.AppHandleExt[i];
                                 p.StartInfo.Arguments = _ServerInfo.wwwroot + ss[].Remove(, ) + ];
                             }
                             break;
                         }
                     }
                 else //ext == ""
                 {
                     p.StartInfo.FileName = _ServerInfo.wwwroot + ss[].Remove(, );
                     p.StartInfo.Arguments = ss[];
                 }

                 p.StartInfo.UseShellExecute = false;
                 p.StartInfo.CreateNoWindow = true;
                 p.StartInfo.RedirectStandardOutput = true;
                 p.StartInfo.WorkingDirectory = p.StartInfo.FileName.Substring(, p.StartInfo.FileName.LastIndexOf();
                 p.Start();
                 string s = p.StandardOutput.ReadToEnd();
                 if (!Directory.Exists(_ServerInfo.wwwroot + _ServerInfo.cacheDIR))
                     Directory.CreateDirectory(_ServerInfo.wwwroot + _ServerInfo.cacheDIR);
                 //ss[0] = ss[0].Substring(ss[0].LastIndexOf("/"));
                 FileStream fs = new FileStream(_ServerInfo.wwwroot + _ServerInfo.cacheDIR + RequestID + p.Id.ToString(),
                     FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
                 fs.Write(Encoding.Default.GetBytes(s), , s.Length);
                 //p.WaitForExit();
                 return fs;
             }
             catch (System.Runtime.InteropServices.ExternalException)
             {
                 IOException e = new IOException();
                 throw e;
             }
             catch (System.SystemException)
             {
                 ArgumentException e = new ArgumentException();
                 throw e;
             }

         }

     }
 }

读取配置文件,根据请求返回内容

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

 using System;
 using System.Collections.Generic;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
 using System.Threading;

 namespace Guying.Project.MiniServer
 {
     /// <summary>
     /// ClientSocketThread 的摘要说明。
     /// </summary>
     public class ClientSocketThread
     {
         public TcpListener tcpl;//Notice: get from SrvMain.tcpl

         private static Encoding ASCII = Encoding.ASCII;
         //private static int RequestID = 0;

         public void HandleThread()
         {
             string strClientIP = "";
             string strClientPort = "";
             string strLocalIP = "";
             string strLocalPort = "";

             Thread currentThread = Thread.CurrentThread;

             try
             {
                 // Accept will block until someone connects
                 Socket s = tcpl.AcceptSocket();
                 //RequestID++;
                 strLocalIP = ((IPEndPoint)s.LocalEndPoint).Address.ToString();
                 strLocalPort = ((IPEndPoint)s.LocalEndPoint).Port.ToString();
                 strClientIP = ((IPEndPoint)s.RemoteEndPoint).Address.ToString();
                 strClientPort = ((IPEndPoint)s.RemoteEndPoint).Port.ToString();

                 RequestProcessor aRequestProcessor = new RequestProcessor(); //Notice:
                 aRequestProcessor.sockSendData = s;//Notice: so that the processor can work
                 aRequestProcessor.RequestID = currentThread.Name;

                 ;//that's enough???
                 Byte[] readclientchar = new Byte[BUFFERSIZE];
                 ] { '\r', '\n' };
                 ];

                 do
                 {
                     //use BUFFERSIZE contral the receive data size to avoid the BufferOverflow attack
                     , BUFFERSIZE, SocketFlags.None);

                     , rc);

                     RequestLines = strReceive.Split(sps);
                     Console.WriteLine(FrmMain.strGMTDateTime() + " Request ID=[{0}] {1}->{2} :{3}",
                         currentThread.Name,
                         ((IPEndPoint)s.RemoteEndPoint).ToString(),
                         ((IPEndPoint)s.LocalEndPoint).ToString(),
                         RequestLines[]);

                 } while (aRequestProcessor.ParseRequestAndProcess(RequestLines));

                 Console.WriteLine(FrmMain.strGMTDateTime() + " Closed ID=[{0}] {1}->{2} :Server Closed", currentThread.Name,
                     ((IPEndPoint)s.LocalEndPoint).ToString(), ((IPEndPoint)s.RemoteEndPoint).ToString());
                 s.Close();
             }
             catch (SocketException)
             {
                 Console.WriteLine(FrmMain.strGMTDateTime() + " Closed ID=[{0}] {1}:{2}->{3}:{4} :Client Closed", currentThread.Name,
                     strClientIP, strClientPort, strLocalIP, strLocalPort);
                 currentThread.Abort();
             }
         }

     }
 }

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

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

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

 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
 using System.Diagnostics;
 using System.Drawing;
 using System.Net;
 using System.Net.Sockets;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
 using System.Windows.Forms;

 namespace Guying.Project.MiniServer
 {
     public partial class FrmMain : Form
     {
         private static FrmMain _FrmMain = null;
         Thread _Thread = null;
         Thread _myWorkerThread = null;

         private FrmMain()
         {
             InitializeComponent();
         }

         public static FrmMain GetInstance()
         {
             if (_FrmMain == null)
             {
                 _FrmMain = new FrmMain();
             }
             return _FrmMain;
         }

         public void ShowMessage(string _messageStr)
         {
             this.listBox_Logs.Items.Add(_messageStr);
         }

         static public string strGMTDateTime()
         {
             DateTime GMTNow = DateTime.Now.ToUniversalTime();
             string month;
             switch (GMTNow.Month)
             {
                 : month = "Jan"; break;
                 : month = "Feb"; break;
                 : month = "Mar"; break;
                 : month = "Apr"; break;
                 : month = "May"; break;
                 : month = "Jun"; break;
                 : month = "Jul"; break;
                 : month = "Aug"; break;
                 : month = "Sep"; break;
                 : month = "Oct"; break;
                 : month = "Nov"; break;
                 : month = "Dec"; break;
                 default: month = "Martian???"; break;
             }
             return
                 GMTNow.DayOfWeek.ToString().Substring(, ) + ", " + GMTNow.Day.ToString() + " " + month + " " + GMTNow.Year.ToString() + " " + GMTNow.Hour.ToString() + ":" + GMTNow.Minute.ToString() + ":" + GMTNow.Second.ToString() + ":" + DateTime.Now.Millisecond.ToString() + " " + "GMT";
         }

         private void btn_Start_Click(object sender, EventArgs e)
         {
             Start();
         }

         void Start()
         {
             try
             {
                 ServerInfo _ServerInfo = new ServerInfo();
                 //i want to block the RequestProcessor when changing  _ServerInfo
                 lock (typeof(RequestProcessor))
                 {
                     RequestProcessor._ServerInfo = _ServerInfo;
                 }

                 ShowMessage("Starting NetWork listening...");

                 this.btn_Stop.Enabled = true;
                 this.btn_Start.Enabled = false;

                 TcpListener tcpListener;

                 try
                 {
                     tcpListener = new TcpListener(IPAddress.Parse(this.cmb_IPAddresses.Text), int.Parse(this.txt_IPPoint.Text)); // listen on port 80
                 }
                 catch (Exception)
                 {
                     ShowMessage("Wrong argument:Using [[IP] (Port)] as the options");
                     return;
                 }
                 tcpListener.Start();

                 Console.WriteLine("Listening on {0}", ((IPEndPoint)tcpListener.LocalEndpoint).ToString());
                 Console.WriteLine("Server now waiting for clients to connect");
                 Console.WriteLine();
                 Console.WriteLine(strGMTDateTime() + " Server Start,Start logging");
                 //Console.WriteLine("Press Ctrl+c to Quit...");

                 ;

                 ThreadStart _ThreadStart = new ThreadStart(() =>
                 {
                     while (true)
                     {
                         while (!tcpListener.Pending())
                         {
                             Thread.Sleep();
                         }

                         ClientSocketThread myThreadHandler = new ClientSocketThread();
                         myThreadHandler.tcpl = tcpListener;//Notice: dont forget do this
                         ThreadStart myThreadStart = new ThreadStart(myThreadHandler.HandleThread);
                         _myWorkerThread = new Thread(myThreadStart);
                         _myWorkerThread.Name = (ThreadID++).ToString();
                         _myWorkerThread.Start();
                     }
                 });

                 _Thread = new Thread(_ThreadStart);
                 _Thread.Start();

             }
             catch (SocketException socketError)
             {
                 )
                 {
                     ShowMessage("Connection to this port failed.  There is another server is listening on this port.");
                 }
             }
             catch (FormatException)
             {
                 ShowMessage("invalid IP Address");
             }
             catch (Exception ex)
             {
                 ShowMessage("Ah O: " + ex.Message);
             }
         }

         private void FrmMain_Load(object sender, EventArgs e)
         {
             if (System.IO.File.Exists(Application.StartupPath + "\\Guying.ssk"))
             {
                 this.skinEngine.SkinFile = Application.StartupPath + "\\Guying.ssk";
                 this.skinEngine.SkinAllForm = true;
             }

             this.btn_Stop.Enabled = false;
             this.btn_Start.Enabled = true;

             this.cmb_IPAddresses.Items.Add("127.0.0.1");

             try
             {
                 this.cmb_IPAddresses.Items.Add(GetOutterIPAddress());
             }
             catch (Exception) { }

             IPAddress[] ipAddresses = Dns.GetHostAddresses(Environment.MachineName);
             foreach (IPAddress ip in ipAddresses)
             {
                 if (ip.AddressFamily == AddressFamily.InterNetwork)
                 {
                     this.cmb_IPAddresses.Items.Add(ip);
                 }
             }
         }

         private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
         {
             Process.GetCurrentProcess().Kill();
         }

         public string GetOutterIPAddress()
         {
             string str = null;
             //这个负责抓IP的页。第一步先抓取这个html页的全部内容
             string url = "http://www.ikaka.com/ip/index.asp";
             WebClient wc = new WebClient();
             wc.Credentials = CredentialCache.DefaultCredentials;
             Byte[] pageData = wc.DownloadData(url);
             string MyUrl = System.Text.Encoding.UTF8.GetString(pageData);
             //正则找到页面中的IP部分,并输出。
             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]))");
             foreach (Match m in regex.Matches(MyUrl))
             {
                 str = m.ToString();
             }
             return str;

         }

         private void btn_Stop_Click(object sender, EventArgs e)
         {
             _Thread.Abort();
             _myWorkerThread.Abort();

             this.btn_Start.Enabled = true;
             this.btn_Stop.Enabled = false;
         }
     }
 }

窗体调用实现方法的代码

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

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

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

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

WinForms 小型HTML服务器的更多相关文章

  1. 小型Http服务器

    HTTP又叫做超文本传输协议,现如今用的最多的版本是1.1版本.HTTP有如下的特点: 支持客户/服务器模式(C/S或B/S) 简单快速:基于请求和响应,请求只需传送请求方法和请求路径 灵活:HTTP ...

  2. C语言构建小型Web服务器

    #include <stdio.h> #include <sys/socket.h> #include <stdlib.h> #include <string ...

  3. Tiny server:小型Web服务器

    一.背景 csapp的网络编程粗略的介绍了关于网络编程的一些知识,在最后的一节主要就实现了一个小型的Webserver.这个server名叫Tiny,它是一个小型的可是功能齐全的Webserver.在 ...

  4. MINI_httpd移植,构建小型WEB服务器

    一.简介 目的:构建小型WEB站,具备SSL. mini_httpd is a small HTTP server. Its performance is not great, but for low ...

  5. HttpListener 实现小型web服务器

    HttpListener 实现web服务器 用于小型服务器,简单.方便.不需要部署. 总共代码量不超过50行. static void Main(string[] args) { //创建HTTP监听 ...

  6. django搭建一个小型的服务器运维网站-拿来即用的bootstrap模板

    目录 项目介绍和源码: 拿来即用的bootstrap模板: 服务器SSH服务配置与python中paramiko的使用: 用户登陆与session; 最简单的实践之修改服务器时间: 查看和修改服务器配 ...

  7. Node fs, url, http 组合小型的服务器 ( 满足html请求, get, post 传值 )

    <script type="text/javascript"> /* * 引入模块 */ var http = require('http'); var url = r ...

  8. 小型云服务器搭建GitLab遇到的坑

    云服务商:腾讯云,搞活动买的 3年800块钱,和同时一人一台 配置:1C.1G.50G 用三年,挺划算的 项目中以前一直使用SVN作为代码版本控制,秉着程序员做到老学到老的精神,想尝试一下先进的GIT ...

  9. 小型web服务器thttpd的学习总结(下)

    1.主函数模块分析 对于主函数而言,概括来说主要做了三点内容,也就是初始化系统,进行系统大循环,退出系统.下面主要简单阐述下在这三个部分,又做了哪些工作呢. 初始化系统 拿出程序的名字(argv[0] ...

随机推荐

  1. Metadata Lock原理3

      http://blog.itpub.net/26515977/viewspace-1208250/   腾讯工程师 随着5.5.3引入MDL,更多的Query被“Waiting for table ...

  2. Python学习 之 包和模块

    1.rpm -ql python #查看python在计算机中安装了哪些文件 2.模块是一个可以导入的Python脚本文件 包是一堆按目录组织的模块和子包,目录下的__init__.py文件存放了包的 ...

  3. 1081. Rational Sum (20)

    the problem is from PAT,which website is http://pat.zju.edu.cn/contests/pat-a-practise/1081 the code ...

  4. 称球问题(zt)

    下面说的这个问题可能大家都看到过,它是这么描述的: 现在有n(n>=2)个球,n个球外观一模一样,但是重量有区别,其中有且仅有一个球的重量比其它n-1个球要重,现在有一个天平,天平是完好无损的, ...

  5. 小白日记35:kali渗透测试之Web渗透-手动漏洞挖掘(一)-默认安装引发的漏洞

    手动漏洞挖掘 即扫描后,如何对发现的漏洞告警进行验证. #默认安装 流传linux操作系统比windows系统安全的说法,是因为windows系统默认安装后,会开放很多服务和无用的端口,而且未经过严格 ...

  6. UrlPathEncode与UrlEncode的区别

    UrlEncode与UrlPathEncode 的基本作用都是对 URL 字符串进行编码 不同点总结如下: 不同点 UrlEncode UrlPathEncode 处理空格的方式 替换成“+” 替换成 ...

  7. Android(java)学习笔记93:Android布局详解之一:FrameLayout

    FrameLayout是最简单的布局了.所有放在布局里的控件,都按照层次堆叠在屏幕的左上角.后加进来的控件覆盖前面的控件. 在FrameLayout布局里,定义任何空间的位置相关的属性都毫无意义.控件 ...

  8. 【Irrlicht鬼火引擎】掌握引擎使用流程,入门程序HelloWorld

    分析 一.简述使用步骤 一般而言,对于一个简单的程序,Irrlicht引擎的一般使用步骤如下: 预处理:(1)包含 <irrlicht.h> 头文件#include <irrlich ...

  9. [改善Java代码]异步运算考虑使用Callable接口

    多线程有两种实现方式: 一种是实现Runnable接口,另一种是继承Thread类,这两种方式都有缺点,run方法没有返回值,不能抛出异常(这两个缺点归根到底是Runable接口的缺陷,Thread也 ...

  10. HttpClient(4.3.5) - HTTP Execution Context

    Originally HTTP has been designed as a stateless, response-request oriented protocol. However, real ...