模拟服务器
一、使用窗体程序写一个简单的UI
后台代码
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Net; 8 using System.Net.Sockets; 9 using System.Text; 10 using System.Threading; 11 using System.Threading.Tasks; 12 using System.Windows.Forms; 13 14 namespace MyWebService 15 { 16 public partial class Form1 : Form 17 { 18 public Form1() 19 { 20 InitializeComponent(); 21 } 22 Socket listenSocket = null; 23 /// <summary> 24 /// 启动服务 25 /// </summary> 26 /// <param name="sender"></param> 27 /// <param name="e"></param> 28 private void BtnStar_Click(object sender, EventArgs e) 29 { 30 listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建监控Socket 31 IPAddress iPAddress = IPAddress.Parse(txtIP.Text);//创建IP地址 32 IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, Convert.ToInt32(txtPort.Text));//创建网络节点 33 listenSocket.Bind(iPEndPoint);//绑定网络节点 34 listenSocket.Listen(10);//监听队列10 35 //只有监听到一个连接,代码才会继续往下走,会影响UI线程,所以开启一个线程专门监听 36 Thread myThread = new Thread(BeginAccept); 37 myThread.IsBackground = true; 38 myThread.Start(); 39 } 40 /// <summary> 41 /// 监听浏览器发送的请求,当有浏览器发送请求时,创建一个新的Socket处理客户请求,使用死循环继续监听下一个用户的请求 42 /// </summary> 43 private void BeginAccept() 44 { 45 while (true)//监听Socket继续监听 46 { 47 Socket socket = listenSocket.Accept();//将连接交给一个新创建的Socket 48 //对请求进行处理 49 HttpApplication httpApplication = new HttpApplication(socket, ShowMsg); 50 } 51 } 52 /// <summary> 53 /// 对跨线程访问进行处理 54 /// </summary> 55 /// <param name="msg"></param> 56 private void ShowMsg(string msg) 57 { 58 if (txtMsg.InvokeRequired) 59 { 60 txtMsg.Invoke(new Action<string>((mgs) => 61 { 62 this.txtMsg.Text = msg+"\r\n"; 63 }), msg); 64 } 65 } 66 } 67 }
使用HttpApplication类对发送来的请求做处理
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Net.Sockets; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace MyWebServer 10 { 11 /// <summary> 12 /// 完成客户端发送过来的数据的处理。 13 /// </summary> 14 public class HttpApplication 15 { 16 Socket newSocket = null; 17 DGShowMsg dgShowMsg = null; 18 /// <summary> 19 /// HttpApplication构造函数 20 /// </summary> 21 /// <param name="newSocket">需要处理的Socket对象</param> 22 /// <param name="dgShowMsg">窗体程序的文本框</param> 23 public HttpApplication(Socket newSocket, DGShowMsg dgShowMsg) 24 { 25 this.newSocket = newSocket; 26 this.dgShowMsg = dgShowMsg; 27 //接收客户端发送过来的数据. 28 byte[] buffer = new byte[1024 * 1024 * 2]; 29 int receiveLength = newSocket.Receive(buffer);//接收客户端发送过来的数据,返回的是实际接收的数据的长度。 30 //如果发过来的请求有数据,才进行处理 31 if (receiveLength > 0) 32 { 33 string msg = System.Text.Encoding.UTF8.GetString(buffer, 0, receiveLength); 34 HttpRequst request = new HttpRequst(msg); 35 ProcessReuest(request); 36 dgShowMsg(msg); 37 } 38 } 39 /// <summary> 40 /// 对请求做处理,并响应 41 /// </summary> 42 /// <param name="request"></param> 43 public void ProcessReuest(HttpRequst request) 44 { 45 string filePath = request.FilePath; 46 string dataDir = AppDomain.CurrentDomain.BaseDirectory;//获得当前服务器程序的运行目录 47 if (dataDir.EndsWith(@"\bin\Debug\") || dataDir.EndsWith(@"\bin\Release\")) 48 { 49 dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName; 50 } 51 string fullDir = dataDir + filePath;//获取文件完整路径。 52 using (FileStream fileStream = new FileStream(fullDir, FileMode.Open, FileAccess.Read)) 53 { 54 byte[] buffer = new byte[fileStream.Length]; 55 fileStream.Read(buffer, 0, buffer.Length); 56 //构建响应报文。 57 HttpResponse response = new HttpResponse(buffer, filePath); 58 newSocket.Send(response.GetHeaderResponse());//返回响应头. 59 newSocket.Send(buffer); 60 } 61 } 62 } 63 }
这是请求报文
GET /Show.html HTTP/1.1
Host: 127.0.0.1:9876
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3554.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
HttpRequest类:对请求报文头进行处理
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace MyWebService 8 { 9 public class HttpRequest 10 { 11 /// <summary> 12 /// 请求文件相对路径 13 /// </summary> 14 public string filePath { get; set; } 15 public HttpRequest(string msg) 16 { 17 filePath = msg.Split(' ')[1]; 18 } 19 } 20 }
HttpResponse类
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace MyWebService 9 { 10 public class HttpResponse 11 { 12 byte[] buffer; 13 /// <summary> 14 /// 报文体返回类型 15 /// </summary> 16 public string Content_Type { get; set; } 17 /// <summary> 18 /// HttpResponse构造函数 19 /// </summary> 20 /// <param name="buffer">报文体字节数组</param> 21 /// <param name="fliePath">文件绝对路径</param> 22 public HttpResponse(byte[] buffer, string fliePath) 23 { 24 this.buffer = buffer; 25 string fileExt = Path.GetExtension(fliePath);//获取响应文件扩展名,返回相应的报文体返回类型 26 switch (fileExt) 27 { 28 case ".html": 29 Content_Type = "text/html"; 30 break; 31 } 32 } 33 /// <summary> 34 /// 获取返回报文头 35 /// </summary> 36 /// <returns></returns> 37 public byte[] GetResonseHead() 38 { 39 StringBuilder builder = new StringBuilder(); 40 builder.Append("HTTP/1.1 200 ok\r\n"); 41 builder.Append("Content-Type:" + Content_Type + ";charset=utf-8\r\n"); 42 builder.Append("Content-Length:" + buffer.Length + "\r\n\r\n");//在相应报文头的最后一行下面有一个空行,所以在这里加两组"\r\n" 43 return System.Text.Encoding.UTF8.GetBytes(builder.ToString()); 44 } 45 } 46 }
Show.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
我的博客.
</body>
</html>
最后我们来用一下
点击启动调试,然后启动服务
然后再浏览器输入,请求地址
最后的结果就是