赞
踩
第二步——将显示消息交由DataConnection类来实现:
//运行服务器 private void btnStart_Click(object sender, EventArgs e) { //创建连接的ip地址 IPAddress ip = IPAddress.Parse(txtIp.Text); //创建连接的ip地址和端口号 IPEndPoint port = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text)); //创建一个基本的socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { //绑定ip和端口号 socket.Bind(port); //监听的最大等待个数 socket.Listen(10); ShowMsg("开始运行了..."); //接收浏览器,将监听封装成一个方法 Thread th = new Thread(Listen); //将监听的这个方法放到线程中,设为后台线程。 th.IsBackground = true; th.Start(socket); } catch (Exception ex) { ShowMsg(ex.Message); } } //监听浏览器的连接 void Listen(object o) { Socket socket = o as Socket; while (true) { //创建负责通信用的socket Socket connSocket = socket.Accept(); ShowMsg(connSocket.RemoteEndPoint.ToString() + "连接成功了"); //接收消息 byte[] buffer = new byte[1024 * 1024]; //实际接收到的字节个数 int num = connSocket.Receive(buffer); string str = Encoding.UTF8.GetString(buffer, 0, num); ShowMsg(str); } }
- //监听浏览器的连接
- void Listen(object o)
- {
- Socket socket = o as Socket;
- while (true)
- {
- //创建负责通信用的socket
- Socket connSocket = socket.Accept();
- ShowMsg(connSocket.RemoteEndPoint.ToString() + "连接成功了");
-
- //接收消息,写到一个DataConnection类中,new一个对象
- //通过DataConnection接收http请求和发送http响应
- DataConnection dc = new DataConnection(connSocket, ShowMsg);
- }
- }
- DataConnection类实现代码:
- //定义一个委托,实现展示消息方法在类与类之间进行传递
- delegate void DelSetText(string msg);
-
- /// <summary>
- /// 1、接收浏览器发送的请求
- /// 2、向浏览器发送响应
- /// </summary>
- class DataConnection
- {
- private Socket connSocket;
- //要指向窗体中给文本框赋值的方法(ShowMsg)
- private DelSetText del;
- //构造函数中把通信用的connsocket,还有委托方法传过来
- //获取浏览器发送过来的http请求
- public DataConnection(Socket connSocket, DelSetText del)
- {
- this.connSocket = connSocket;
- this.del = del;
-
- //2、执行接收消息的方法
- string msg = RecMsg();
- //把消息——http请求报文显示在文本框中
- del(msg);
- }
-
- //接收消息
- string RecMsg()
- {
- //接收消息
- byte[] buffer = new byte[1024 * 1024];
- //实际接收到的字节个数
- int num = connSocket.Receive(buffer);
- string str = Encoding.UTF8.GetString(buffer, 0, num);
- return str;
- }
第三步——DataConnection类分析请求报文并根据请求路径返回具体页面:- //定义一个委托,实现展示消息方法在类与类之间进行传递
- delegate void DelSetText(string msg);
-
- /// <summary>
- /// 1、接收浏览器发送的请求
- /// 2、向浏览器发送响应
- /// </summary>
- class DataConnection
- {
- private Socket connSocket;
- //要指向窗体中给文本框赋值的方法(ShowMsg)
- private DelSetText del;
- //构造函数中把通信用的connsocket,还有委托方法传过来
- //获取浏览器发送过来的http请求
- public DataConnection(Socket connSocket, DelSetText del)
- {
- this.connSocket = connSocket;
- this.del = del;
-
- //2、执行接收消息的方法
- string msg = RecMsg();
- //把消息——http请求报文显示在文本框中
- del(msg);
-
- //3、分析http请求报文,写到一个Request类中
- Request req = new Request(msg);
- //GET /1.html HTTP/1.1
- //req.Url相对路径 /1.html
-
- //4、根据请求的路径,判断是静态页面还是动态页面
- Judge(req.Url);
- }
- Request类中实现代码:
- /// <summary>
- /// 解析请求报文中的url
- /// </summary>
- class Request
- {
- /// <summary>
- /// 解析msg中的url
- /// </summary>
- /// <param name="msg">请求报文</param>
- public Request(string msg)
- {
- try
- {
- //以行分割请求报文
- string[] arrMsg = msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
- //请求报文中的请求行
- string firstLine = arrMsg[0];
- //以空格分割请求报文中的请求行
- string[] arr = firstLine.Split(' ');
- //获得请求行中的路径
- url = arr[1];
- }
- catch (Exception ex)
- {
- url = "";
- }
- }
- private string url;
- /// <summary>
- /// 请求行中的路径
- /// </summary>
- public string Url
- {
- get { return url; }
- set { url = value; }
- }
- }
第四步——DataConnection类中将生成响应头交由Response类实现:- Response类实现代码:
- /// <summary>
- /// 准备响应头
- /// </summary>
- class Response
- {
- //用来存放状态码和状态描述
- private Dictionary<int, string> dic = new Dictionary<int, string>();
- //状态码
- private int statusCode = 200;
- //内容的长度
- private int contentLength;
- //内容的类型
- private string contentType;
- //调用构造方法,获得状态码、内容的长度和内容的类型。
- public Response(int statusCode, int contentLength, string url)
- {
- //填充字典,状态码和状态码的描述
- FillDic();
- //状态码
- this.statusCode = statusCode;
- //内容的长度
- this.contentLength = contentLength;
- //调用方法来获得内容的类型
- GetContentType(url);
- }
-
- //填充字典,状态码和状态码描述对应的键值对
- void FillDic()
- {
- dic.Add(200, "OK");
- dic.Add(404, "Not Found");
- }
-
- //根据后缀给contentType内容类型赋值
- void GetContentType(string url)
- {
- //.htm
- string ext = Path.GetExtension(url);
- switch (ext)
- {
- case ".htm":
- case ".html":
- contentType = "text/html";
- break;
- case ".css":
- contentType = "text/css";
- break;
- case ".js":
- contentType = "text/javascript";
- break;
- case ".jpg":
- contentType = "image/jpeg";
- break;
- default:
- contentType = "text/html";
- break;
- }
- }
-
- //生成响应头
- public byte[] GetResponseHeaders()
- {
- //HTTP/1.1 200 OK
- //Content-Length: 427380
- //Content-Type: image/jpeg;charset=utf-8
- StringBuilder sb = new StringBuilder();
- sb.AppendLine("HTTP/1.1 " + statusCode + " " + dic[statusCode]);
- sb.AppendLine("Content-Length: " + contentLength);
- sb.AppendLine("Content-Type: " + contentType + ";charset=utf-8\r\n");
- return Encoding.UTF8.GetBytes(sb.ToString());
- }
- }
第五步——DataConnection类中接收响应头并且处理静态页面:- //根据请求的路径,判断是静态页面还是动态页面
- void Judge(string url)
- {
- //.htm
- string ext = Path.GetExtension(url).TrimStart('.');
- switch (ext.ToLower())
- {
- case "htm":
- case "html":
- case "jpg":
- case "js":
- case "gif":
- case "png":
- //处理静态页面 并作出响应
- ProcessStaticPage(url);
- break;
- case "aspx": //jsp php
- //处理动态页面
- ProcessDyPage(url);
- break;
- default:
- break;
- }
- }
-
- /// <summary>
- /// 根据路径找到静态页面,并作出响应
- /// 1 获得响应头
- /// </summary>
- /// <param name="url"></param>
- void ProcessStaticPage(string url)
- {
- // /1.htm
- //1、根据相对路径生成绝对路径
- //1.1、获取exe所在文件夹的路径
- string exePath = AppDomain.CurrentDomain.BaseDirectory;
- //1.2、请求文件的绝对路径
- string path = exePath + "Web\\" + url;
- //2、判断文件是否存在,读取静态页面
- if (File.Exists(path))
- {
- using (FileStream fs = new FileStream(path, FileMode.Open))
- {
- //2.1、读取文件
- byte[] buffer = new byte[fs.Length];
- fs.Read(buffer, 0, buffer.Length);
- //2.2、生成响应头
- Response response = new Response(200, buffer.Length, url);
- //注意:send没有立即发送,会等待一个非常短的时间,等待是否还有send,如果有,一起发送过去。
- //2.3、发送响应头
- connSocket.Send(response.GetResponseHeaders());
- //2.4、发送响应体
- connSocket.Send(buffer);
- //2.5、关闭短连接
- connSocket.Close();
- del("关闭连接");
- }
- }
- else
- {
- //404文件不存在
- }
- }
第六步——DataConnection类中处理动态页面:
//处理动态页面 void ProcessDyPage(string url) { NewsList list = new NewsList(); //响应体 byte[] buffer = list.ProcessRequest(); //响应头 Response res = new Response(200, buffer.Length, url); //发送响应头 connSocket.Send(res.GetResponseHeaders()); //发送响应体 connSocket.Send(buffer); //关闭短连接 connSocket.Close(); del("关闭连接了"); } 此方法,只要请求的的页面是以.aspx结尾的,不管什么名字,都可访问得到。 因为是根据后缀名来找到页面。
第七步——DataConnection类中处理动态页面完善:
- //处理动态页面
- void ProcessDyPage(string url)
- {
- //文件名(类名)
- string fileName = Path.GetFileNameWithoutExtension(url);
-
- #region 第一种处理动态页面方式
- 定义一个接口
- //IHttpHandler handler = null;
- 判断
- //if (fileName.ToLower() == "newslist")
- //{
- // //NewsList list = new NewsList();
- // //去实现一个接口
- // handler = new NewsList();
- //}
- //else if (fileName.ToLower() == "newsdetails")
- //{
- // //NewsDetails details = new NewsDetails();
- // //去实现一个接口
- // handler = new NewsDetails();
- //}
- //if (handler != null)
- //{
- // //响应体
- // byte[] buffer = handler.ProcessRequest();
- // //响应头
- // Response res = new Response(200, buffer.Length, url);
- // //发送响应头
- // connSocket.Send(res.GetResponseHeaders());
- // //发送响应体
- // connSocket.Send(buffer);
- // //关闭短连接
- // connSocket.Close();
- // del("关闭连接了");
- //}
- //else
- //{
- // //404 找不到页面
- //}
- #endregion
-
- #region 第二种处理动态页面的方式
- //通过反射创建负责请求类的对象,并且放到接口中
- //根据字符串(类的全名称:命名空间.类名)创建对应类的对象
- //命名空间
- string nameSpace =
- System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
- //类的全名称
- string fullName = nameSpace + "." + fileName;
- //通过反射创建类的对象
- IHttpHandler handler = System.
- Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullName, true) as IHttpHandler;
-
- if (handler != null)
- {
- //生成响应体
- byte[] buffer = handler.ProcessRequest();
- //响应头
- Response res = new Response(200, buffer.Length, url);
- //发送响应头
- connSocket.Send(res.GetResponseHeaders());
- //发送响应体
- connSocket.Send(buffer);
- //关闭短连接
- connSocket.Close();
- del("关闭连接了");
- }
- else
- {
- //404文件不存在
- }
- #endregion
- }
- 准备一个接口IHttpHandler:
- /// <summary>
- /// 让实现了接口的类,能够处理浏览器的请求
- /// </summary>
- interface IHttpHandler
- {
- //处理请求并做出响应
- byte[] ProcessRequest();
- }
附上代码整个程序
备注:写于2013年9月25日
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。