c#原始提供了http的监听的类HttpListener,实现了简单的http。文章地址《C# 控制台或者winform程序开启http的监听状态》
但是经过我测试,这个HttpListener提供的真的就只是简单的http监听功能,无法实现高并发处理。
不知道是我处理问题还是其他什么原因,无法实现,当上一个http请求连接尚未关闭的情况下,即便是把请求放到另外一个线程执行,都要等到处理结束,close了才能接受和处理下一次的连接请求。
也许你会说HttpListener不是提供了异步监听的嘛?异步不就可以类使用多线程实现嘛。但是经过我测试,确实没有得到我想要的实际效果。
所以另辟蹊径。http其实质就是socket的tcp封装实现的功能,单次请求,处理,关闭的socket功能。
所以这里找到了可以使用最原始的socket的来提供http监听,处理数据,关闭状态。
好了直接上代码,,一下代码部分来至于博客园,园友帖子提供,时间久远亦不知道是哪位仁兄的帖子,见谅。
internal class HttpServer { private IPEndPoint _IP; private TcpListener _Listeners; private volatile bool IsInit = false; HashSet<string> Names; /// <summary> /// 初始化服务器 /// </summary> public HttpServer(string ip, int port, HashSet<string> names) { IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(ip), port); this._IP = localEP; Names = names; if (Names == null) { Names = new HashSet<string>(); } try { foreach (var item in names) { Console.WriteLine(string.Format(System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff:") + "Start Listen Http Socket -> {0}:{1}{2} ", ip, port, item)); } this._Listeners = new TcpListener(IPAddress.Parse(ip), port); ); IsInit = true; this.AcceptAsync(); } catch (Exception ex) { Console.WriteLine(ex); this.Dispose(); } } private void AcceptAsync() { try { this._Listeners.BeginAcceptTcpClient(new AsyncCallback(AcceptAsync_Async), null); } catch (Exception) { } } private void AcceptAsync_Async(IAsyncResult iar) { this.AcceptAsync(); try { TcpClient client = this._Listeners.EndAcceptTcpClient(iar); var socket = new HttpClient(client); Console.WriteLine(System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff:") + "Create Http Socket Remote Socket LocalEndPoint:" + client.Client.LocalEndPoint + " RemoteEndPoint:" + client.Client.RemoteEndPoint.ToString()); foreach (var item in Names) { if (socket.http_url.StartsWith(item)) { try { socket.process(); return; } catch { break; } } } socket.WriteFailure(); socket.Close(); } catch (Exception) { } } /// <summary> /// 释放资源 /// </summary> public void Dispose() { if (IsInit) { IsInit = false; this.Dispose(true); GC.SuppressFinalize(this); } } /// <summary> /// 释放所占用的资源 /// </summary> /// <param name="flag1"></param> protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1) { if (flag1) { if (_Listeners != null) { try { Console.WriteLine(string.Format("Stop Http Listener -> {0}:{1} ", this.IP.Address.ToString(), this.IP.Port)); _Listeners.Stop(); _Listeners = null; } catch { } } } } /// <summary> /// 获取绑定终结点 /// </summary> public IPEndPoint IP { get { return this._IP; } } }
这个是实现socket监听状态
public class HttpClient { * * ; // 10MB ; private Stream inputStream; public StreamWriter OutputStream; public String http_method; public String http_url; public String http_protocol_versionstring; public Hashtable httpHeaders = new Hashtable(); internal TcpClient _Socket; /// <summary> /// 这个是服务器收到有效链接初始化 /// </summary> internal HttpClient(TcpClient client) { this._Socket = client; inputStream = new BufferedStream(_Socket.GetStream()); OutputStream = new StreamWriter(new BufferedStream(_Socket.GetStream()), UTF8Encoding.Default); ParseRequest(); } internal void process() { try { if (http_method.Equals("GET")) { Program.Pool.ActiveHttp(this, GetRequestExec()); } else if (http_method.Equals("POST")) { Program.Pool.ActiveHttp(this, PostRequestExec()); } } catch (Exception e) { Console.WriteLine("Exception: " + e.ToString()); WriteFailure(); } } public void Close() { OutputStream.Flush(); inputStream.Dispose(); inputStream = null; OutputStream.Dispose(); OutputStream = null; // bs = null; this._Socket.Close(); } #region 读取流的一行 private string ReadLine() /// <summary> /// 读取流的一行 /// </summary> /// <returns></returns> private string ReadLine() { int next_char; string data = ""; while (true) { next_char = this.inputStream.ReadByte(); if (next_char == '\n') { break; } if (next_char == '\r') { continue; } ) { Thread.Sleep(); continue; }; data += Convert.ToChar(next_char); } return data; } #endregion #region 转化出 Request private void ParseRequest() /// <summary> /// 转化出 Request /// </summary> private void ParseRequest() { String request = ReadLine(); if (request != null) { string[] tokens = request.Split(' '); ) { throw new Exception("invalid http request line"); } http_method = tokens[].ToUpper(); http_url = tokens[]; http_protocol_versionstring = tokens[]; } String line; while ((line = ReadLine()) != null) { if (line.Equals("")) { break; } int separator = line.IndexOf(':'); ) { throw new Exception("invalid http header line: " + line); } String name = line.Substring(, separator); ; while ((pos < line.Length) && (line[pos] == ' ')) { pos++;//过滤键值对的空格 } string value = line.Substring(pos, line.Length - pos); httpHeaders[name] = value; } } #endregion #region 读取Get数据 private Dictionary<string, string> GetRequestExec() /// <summary> /// 读取Get数据 /// </summary> /// <returns></returns> private Dictionary<string, string> GetRequestExec() { Dictionary<string, string> datas = new Dictionary<string, string>(); ); ) { ); datas = getData(data); } WriteSuccess(); return datas; } #endregion #region 读取提交的数据 private void handlePOSTRequest() /// <summary> /// 读取提交的数据 /// </summary> private Dictionary<string, string> PostRequestExec() { ; MemoryStream ms = new MemoryStream(); if (this.httpHeaders.ContainsKey("Content-Length")) { //内容的长度 content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]); if (content_len > MAX_POST_SIZE) { throw new Exception(String.Format("POST Content-Length({0}) 对于这个简单的服务器太大", content_len)); } byte[] buf = new byte[BUF_SIZE]; int to_read = content_len; ) { , Math.Min(BUF_SIZE, to_read)); ) { ) { break; } else { throw new Exception("client disconnected during post"); } } to_read -= numread; ms.Write(buf, , numread); } ms.Seek(, SeekOrigin.Begin); } WriteSuccess(); StreamReader inputData = new StreamReader(ms); string data = inputData.ReadToEnd(); return getData(data); } #endregion #region 输出状态 /// <summary> /// 输出200状态 /// </summary> public void WriteSuccess() { OutputStream.WriteLine("HTTP/1.0 200 OK"); OutputStream.WriteLine("Content-Type: text/html"); OutputStream.WriteLine("Connection: close"); OutputStream.WriteLine(""); } /// <summary> /// 输出状态404 /// </summary> public void WriteFailure() { OutputStream.WriteLine("HTTP/1.0 404 File not found"); OutputStream.WriteLine("Content-Type: text/html"); OutputStream.WriteLine("Connection: close"); OutputStream.WriteLine(""); } #endregion /// <summary> /// 分析http提交数据分割 /// </summary> /// <param name="rawData"></param> /// <returns></returns> private static Dictionary<string, string> getData(string rawData) { var rets = new Dictionary<string, string>(); string[] rawParams = rawData.Split('&'); foreach (string param in rawParams) { string[] kvPair = param.Split('='); ]; ]); rets[key] = value; } return rets; } }
实现了对http数据请求处理
public interface ISocketPool { /// <summary> /// /// </summary> /// <param name="client"></param> void ActiveHttp(Fly.Network.SocketPool.Http.HttpClient client, Dictionary<string, string> parms); }
public class Program { public static MessagePool Pool = new MessagePool(); static void Main(string[] args) { HttpServer https = , new HashSet<string>() {"/test/","/flie/" }); Console.ReadLine(); } } class MessagePool : ISocketPool { public void ActiveHttp(HttpClient client, Dictionary<string, string> parms) { Thread.Sleep(, )); foreach (var item in parms) { Console.WriteLine(DateTime.Now.NowString() + "item.Key:" + item.Key + "; item.Value:" + item.Value); } string strHtml = @" <html><head></head> <body> <div> </div> <div> </div> <div> </div> <div> </div> <div> </div> {0} </body> </html> "; client.OutputStream.WriteLine(string.Format(strHtml, DateTime.Now.NowString() + "xxxxxxxxxxx")); client.Close(); } }
程序启动过后,看到输出
-- ::::Start Listen Http Socket -> /test/ -- ::::Start Listen Http Socket -> /flie/
接下来我们在浏览器输入 127.0.0.1/test/
正常收到请求,输出程序
127.0.0.1/test/
这里test1这个并不是我们监听饿目录,根本不会处理,
接下来我们再看看这个效果 get提交的参数 127.0.0.1/test/?bb=test
输出了get提交过来的参数信息。可能你会奇怪,为什么一次请求会收到两次连接请求。这里我查看过了其中一次请求是浏览器自带的请求页面标签的icon连接请求,
如果你拷贝了程序,你现在可以实现跑来程序,然后输入网址,按着F5不放,看看服务器的承受能力,当然这里忽律了逻辑方面对cpu内存消耗和时间消耗问题。
测试看看吧。