下面是我个人对Web服务器开发流程的一点理解,下面做出了大概的模型,实现了基本的功能,下面也有所有的代码可以提供参考;
一开始学的时候不要把网站想的太复杂了,把网站的流程和大概的原理框架搞清楚,在通过代码大概的实现出来,这样以后面对网站开发的时候就会有一个具体的模型。
网站是一种通讯工具,就像布告栏一样,人们可以通过网站来发布自己想要公开的资讯,或者利用网站来提供相关的网络服务。人们可以通过网页浏览器来访问网站,获取自己需要的资讯或者享受网络服务。
其实Web服务器网站开发无非就是接收到客户端发送过来的请求页面,然后对报文进行有必要的处理,在这个过程可以用事件管道处理来提高扩展性,在重新组装成新的报文,把它按照指定的报文格式发送回客户端去,而浏览器就可以得到响应,接收到想要的数据页面,同时,网站服务将关闭,等有新的请求的时候在开启服务。这个是客户端请求网站数据时的大概过程。
代码都有详细的注释,我就不多列外写了。
当然,这只是我个人的一点理解,我也是初学者,所以仅供参考,有不对的地方也可以指出。
forMyServer网站主页
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace MyServer { public partial class forMyServer : Form { public forMyServer() { InitializeComponent(); } private Sites sites = null;//站点实体 BinaryFormatter formatter = null;//序列化 private void menuAdd_Click(object sender, EventArgs e) { forAddServer f = new forAddServer(); f.SiteEvent += ServerSite;//添加事件 f.ShowDialog(); } private void ServerSite(Site s)//事件处理 { treeView1.Nodes.Clear(); sites.Add(s); string fileName = "a.dat";//序列化文件名(随便取的) string path = Application.ExecutablePath;//获取路劲 path = path.Substring(, path.LastIndexOf('\\')); fileName = path + "\\" + fileName;//带路径的文件名 using (FileStream fs = new FileStream(fileName, FileMode.Create)) { formatter = new BinaryFormatter(); formatter.Serialize(fs, sites);//序列化对象 } TreeNode root = new TreeNode("所有站点"); treeView1.Nodes.Add(root); foreach(Site site in sites)//添加站点到属性控件 { TreeNode node = new TreeNode(site.SiteName); node.Tag = site; root.Nodes.Add(node); } } private void forMyServer_Load(object sender, EventArgs e) { string fileName = "a.dat"; string path = Application.ExecutablePath; path = path.Substring(, path.LastIndexOf('\\')); fileName = path + "\\" + fileName; sites = new Sites(); if (!File.Exists(fileName)) File.Create(fileName); using (FileStream fs = new FileStream(fileName, FileMode.Open)) { if (sites != null) { formatter = new BinaryFormatter(); sites = formatter.Deserialize(fs) as Sites; TreeNode root = new TreeNode("所有站点"); treeView1.Nodes.Add(root); foreach (Site s in sites) { TreeNode node = new TreeNode(s.SiteName); node.Tag = s; root.Nodes.Add(node); } } } } private void menuStart_Click(object sender, EventArgs e) { //取出树形控件中选中的站点 ) { //取出用户选中的站点对象 Site currSite = treeView1.SelectedNode.Tag as Site; //站点没有开启就开启 if (!currSite.IsStart) { ParameterizedThreadStart p = new ParameterizedThreadStart(ListenSocket); Thread t1 = new Thread(p); t1.Start(currSite);//开启一个线程 } } } public void ListenSocket(object currSite) //监听Ip地址 { Site s = currSite as Site; Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint endPoint = ); server.Bind(endPoint); server.Listen();//开启监听 s.IsStart = true;//表示以开启此站点,不用开启 HttpContext h = new HttpContext(); h.SitePath = s.Path; while(true) { Socket client = server.Accept();//接收用户实例 h.TxSocket = client; Thread t = new Thread(Process); t.Start(h); } } public void Process(object c)//发送页面回去的处理流程 { HttpContext h = c as HttpContext; Socket client = h.TxSocket; ]; int length = client.Receive(b); , length);//得到报文 h.Info = new HttpInfo(str);//拆分报文 h.Response = new HttpResponse();//组装新的报文 HttpAllContext allContext = new HttpAllContext();//所有信息 h.Context = allContext; HttpFactory.CreateHandler(h); allContext.ProcessPage(h);//触发事件 client.Send(h.Response.b);//发送数据 client.Close();//关闭服务 } private void 退出服务ToolStripMenuItem_Click(object sender, EventArgs e) { Application.Exit(); } } }
forAddServer添加网站
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MyServer { public partial class forAddServer : Form { public forAddServer() { InitializeComponent(); } public delegate void SiteDelegate(Site s); public event SiteDelegate SiteEvent; private void btnBrowse_Click(object sender, EventArgs e) { FolderBrowserDialog open = new FolderBrowserDialog(); DialogResult result = open.ShowDialog(); if(result == DialogResult.OK)//获得站点路径 { txtDirectory.Text = open.SelectedPath; } } private bool Valid(out string info) //判断格式 { //此处没有做特殊处理,所以我在次提醒读者们 bool flag = true; if (txtName.Text == "" || txtIP.Text == "" || txtPort.Text == "") { flag = false; info = "不能为空"; } else info = "添加成功!"; return flag; } private void btnOK_Click(object sender, EventArgs e) { string info; if (Valid(out info)) MessageBox.Show(info); else { MessageBox.Show(info); return; } Site s = new Site() { SiteName=txtName.Text, IpAddress=txtIP.Text, Path=txtDirectory.Text, Port=txtPort.Text, IsStart=false }; SiteEvent(s); } private void btnCancel_Click(object sender, EventArgs e) { this.Close(); } } }
Site站点类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { [Serializable] public class Site//站点 { public string SiteName { get;set; } public string IpAddress { get; set; } public string Port { get; set; } public string Path { get; set; } [NonSerialized] public bool IsStart; } }
Sites站点集合
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { [Serializable] public class Sites : List<Site> { //public List<Site> sites = new List<Site>(); //public Sites(Site s) //{ // sites.Add(s); //} } }
HttpInfo拆分报文
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { public class HttpInfo { public string Method { get; set; }//GET POST public string Url { get; set; } //请求地址URL public string Protocol { get; set; }//使用的协议 public string Other { get; set; }//其它 public HttpInfo(string str) { string[] keys = str.Split(new string[] { "\r\n" }, StringSplitOptions.None); ].Split(' ');//GET /1.html HTTP/1.1 ];//获取Get/Post方法 ].Substring(); ]; this.Other = str; } } }
Response反应的内容
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { public class HttpResponse { public byte[] b = null; public string CreateOutHtml(string html) { StringBuilder sb = new StringBuilder(); sb.Append("HTTP/1.1 200 OK\r\n"); sb.Append("Content-Type: text/html\r\n"); sb.Append("Last-Modified: Mon, 02 Dec 2013 12:21:06 GMT\r\n"); sb.Append("Accept-Ranges: bytes\r\n"); sb.Append("Server: Microsoft-IIS/7.5\r\n"); sb.Append("Content-Length: 426\r\n\r\n"); sb.Append(html);//连接上报文头部 return html; } } }
HttpContext内容实体
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace MyServer { public class HttpContext { public string SitePath { get; set; }//路径地址 public Socket TxSocket { get; set; } public HttpResponse Response { get; set; }//全部报文 public HttpInfo Info { get; set; }//拆分报文获得想要的信息 public HttpAllContext Context { get; set; } } }
HttpAllContext请求事件处理
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MyServer { public class HttpAllContext { public delegate void ValidUserDelegate(HttpContext context); public delegate void LoadCache(HttpContext context); public delegate void LoadStatus(HttpContext context); public delegate void GeneratePage(HttpContext context); public delegate void WriteStatus(HttpContext context); //生成页面 public event ValidUserDelegate ValidUserHandler;//报文头 public event LoadCache LoadCacheHandler; public event LoadStatus LoadStatusHandler; public event GeneratePage GeneratePageHandler; //生成页面 public event WriteStatus WriteStatusHandler;//状态 //获取请求的参数:从context.Request //生成的页面:context.Response //支持客户自定义处理方式,扩展性-----事件 “管道技术” public void ProcessPage(HttpContext context) { if (ValidUserHandler != null) ValidUserHandler(context); if (LoadCacheHandler != null) LoadCacheHandler(context); if (LoadStatusHandler != null) LoadStatusHandler(context); if (GeneratePageHandler != null) GeneratePageHandler(context); if (WriteStatusHandler != null) WriteStatusHandler(context); } } }
HttpFactory工厂类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { public abstract class HttpFactory { public static void CreateHandler(HttpContext con) { IHttpHead head = null; //获取该文件的后缀类型 xxx.html string extName = con.Info.Url.Substring(con.Info.Url.LastIndexOf('.')); switch (extName) { case ".html": head = new HtmlHead(); break; //case ".js": head = new JsHead(); break; } //添加事件 con.Context.GeneratePageHandler += head.Process; } } }
IHttpHead//定义一个借口
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyServer { public interface IHttpHead { void Process(HttpContext con); } }
HtmlHead子类
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace MyServer { public class HtmlHead : IHttpHead { public void Process(HttpContext context) { HttpInfo httpInfo = context.Info;//拆分报文类获得地址等 //从报文中拆出请求的带路径html文件名 string htmlFileName = context.SitePath + "\\" + httpInfo.Url; //如果有这个请求的文件就往下执行 if (File.Exists(htmlFileName)) { //读取文件中的所有内容 string html = File.ReadAllText(htmlFileName); //重新组装报文 html = context.Response.CreateOutHtml(html); byte[] bb = Encoding.UTF8.GetBytes(html); context.Response.b = bb; MessageBox.Show("请求成功!"); } else { } } } }