Socket 简易静态服务器 WPF MVVM模式(四)
最重要的一个类Socket类
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace 简易静态服务器.Code { public class Server { public string GetStockString { get; private set; } private bool runing = false; private Socket ServerSocket; private int timeout = 10; private string fileurl; private Encoding DataToString = Encoding.UTF8; private string RequestedFile = string.Empty; public bool Start(IPAddress Ip,int prot,int Count,string fileurl) { if (runing) return false; try { ServerSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);//监听类型 ServerSocket.Bind(new IPEndPoint(Ip,prot)); ServerSocket.Listen(Count);//监听实例的数量 ServerSocket.ReceiveTimeout = timeout;//超时 ServerSocket.SendTimeout = timeout;//超时 runing = true; this.fileurl = fileurl; } catch { return false; } Thread requestListenerThread = new Thread(() =>{ //多线程进行处理 while (runing) //设置一直开启 { Socket clientSocket; try { clientSocket = ServerSocket.Accept();//等待接收数据 是方法内部的线程堵塞 var Handler = new Thread(() => { clientSocket.ReceiveTimeout = timeout; clientSocket.SendTimeout = timeout; try { GetData(clientSocket); } catch { try { clientSocket.Close(); } catch { } } }); Handler.Start(); } catch { } } }); requestListenerThread.Start(); return true; } public void Stop() { if(runing) { runing = false; try { ServerSocket.Close(); } catch { } ServerSocket.Dispose(); ServerSocket = null; } } private void GetData(Socket dataSocket) { var bytedata = new byte[10240];//10KB的接受消息量 int dataCount = dataSocket.Receive(bytedata);//转换消息 string strReceived = DataToString.GetString(bytedata, 0, dataCount);//转换字节到string GetStockString = strReceived; OnStocketStringChange?.Invoke(strReceived);//事件传递参数到viewmodel string httpmethod = strReceived.Substring(0, strReceived.IndexOf(" "));//获取第一个空格到起始位置之间所有的字符 int StartMethodUrl = strReceived.IndexOf(httpmethod) + httpmethod.Length + 1;//获取请求内容的起始位置。也是直接写作httpmethod.length+1 int EndMethodUrl = strReceived.Substring(0, strReceived.IndexOf("\r\n")).IndexOf("HTTP") - StartMethodUrl; //strReceived.LastIndexOf("HTTP") - StartMethodUrl - 1; string MethodUrl = strReceived.Substring(StartMethodUrl, EndMethodUrl);//获取请求内容 switch(httpmethod) { case "GET": case "POST": RequestedFile = MethodUrl; break; default: dataSocket.Close();//此处也可以是 NotImplemented(dataSocket); return; } RequestedFile = RequestedFile.Replace("/", "\\").Replace("\\..", "");//替换斜杠 RequestedFile = RequestedFile.Split('?')[0];//分割字符串 也可以是RequestedFile.Split('?').Length>1?RequestedFile.Split('?')[0]:RequestedFile; int TypeNameStart =RequestedFile.LastIndexOf(".") + 1; int TypeNameLength = 0; string Extension = "."; switch(TypeNameStart>0) { case true: TypeNameLength = RequestedFile.Length - TypeNameStart; Extension += RequestedFile.Substring(TypeNameStart, TypeNameLength).Replace(" ","");//获取请求格式的字符串 switch (MimeType.Type.ContainsKey(Extension))//判断是否存在这个类型 { case true: switch(File.Exists(fileurl+RequestedFile)) { case true: SendOKResponse(dataSocket,File.ReadAllBytes(fileurl + RequestedFile), MimeType.Type[Extension]); break; case false: NotFound(dataSocket); break; } break; case false: //不存在的话 那是否直接存在这个文件? if (File.Exists(fileurl + RequestedFile))//存在输出 SendOKResponse(dataSocket, File.ReadAllBytes(fileurl + RequestedFile), "text/html"); else//不存在 501 NotImplemented(dataSocket); break; } break; case false: SendOKResponse(dataSocket, File.ReadAllBytes(fileurl + "\\Index.html"), "text/html"); //直接输出index页面 break; } } private void NotFound(Socket clientSocket) { SendResponse(clientSocket, "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><h2>Atasoy Simple Web Server</h2><div>404 - Not Found</div></body></html>", "404 Not Found", "text/html"); } private void NotImplemented(Socket clientSocket) { SendResponse(clientSocket, "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><h2>Atasoy Simple Web Server</h2><div>501 - Method Not Implemented</div></body></html>", "501 Not Implemented", "text/html"); } private void SendResponse(Socket clientSocket, string strContent, string responseCode, string contentType) { byte[] bContent = DataToString.GetBytes(strContent); SendResponse(clientSocket, bContent, responseCode, contentType); } private void SendOKResponse(Socket Send, byte[] SendContent, string SendContentType) =>SendResponse(Send,SendContent,简易静态服务器.Models.SendContentType.GetSendString(Models.SendType.Send200OK),SendContentType); private void SendResponse(Socket Send, byte[] SendContent, string SendCode, string SendContentType) { try { //处理头部 var header=DataToString.GetBytes("HTTP/1.1 " + SendCode + "\r\n" + "Server: Atasoy Simple Web Server\r\n" + "Content-Length: " +SendContent.Length.ToString() + "\r\n" + "Connection: close\r\n" + "Content-Type: " + SendContentType + "\r\n\r\n"); var AllDataByte = new byte[SendContent.Length + header.Length];//复制两个数组 Buffer.BlockCopy(header, 0, AllDataByte, 0, header.Length); Buffer.BlockCopy(SendContent, 0, AllDataByte, header.Length, SendContent.Length); Send.Send(AllDataByte);//发送 Send.Close(); } catch { } } public delegate void StocketStringChange(string sender);//委托 public event StocketStringChange OnStocketStringChange;//事件 } }
基本的模式就是
开始监听
利用两个线程来处理信息
因为socket的accept自带线程堵塞,不会造成线程的大量拥堵。
此外还可以异步进行消息接受,发送
对于socket的基本使用差不多如此。
最重要的是对消息的处理