zoukankan      html  css  js  c++  java
  • C# 利用socekt做到http监听,怎么样才能做到高性能

    c#原始提供了http的监听的类HttpListener,实现了简单的http。文章地址《C# 控制台或者winform程序开启http的监听状态》

    但是经过我测试,这个HttpListener提供的真的就只是简单的http监听功能,无法实现高并发处理。

    不知道是我处理问题还是其他什么原因,无法实现,当上一个http请求连接尚未关闭的情况下,即便是把请求放到另外一个线程执行,都要等到处理结束,close了才能接受和处理下一次的连接请求。

    也许你会说HttpListener不是提供了异步监听的嘛?异步不就可以类使用多线程实现嘛。但是经过我测试,确实没有得到我想要的实际效果。

    所以另辟蹊径。http其实质就是socket的tcp封装实现的功能,单次请求,处理,关闭的socket功能。

    所以这里找到了可以使用最原始的socket的来提供http监听,处理数据,关闭状态。

    好了直接上代码,,一下代码部分来至于博客园,园友帖子提供,时间久远亦不知道是哪位仁兄的帖子,见谅。

      1   internal class HttpServer
      2     {
      3         private IPEndPoint _IP;
      4         private TcpListener _Listeners;
      5         private volatile bool IsInit = false;
      6         HashSet<string> Names;
      7 
      8         /// <summary>
      9         /// 初始化服务器
     10         /// </summary>
     11         public HttpServer(string ip, int port, HashSet<string> names)
     12         {
     13             IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(ip), port);
     14             this._IP = localEP;
     15             Names = names;
     16             if (Names == null)
     17             {
     18                 Names = new HashSet<string>();
     19             }
     20             try
     21             {
     22                 foreach (var item in names)
     23                 {
     24                     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));
     25                 }
     26                 this._Listeners = new TcpListener(IPAddress.Parse(ip), port);
     27                 this._Listeners.Start(5000);
     28                 IsInit = true;
     29                 this.AcceptAsync();
     30             }
     31             catch (Exception ex)
     32             {
     33                 Console.WriteLine(ex);
     34                 this.Dispose();
     35             }
     36         }
     37 
     38         private void AcceptAsync()
     39         {
     40             try
     41             {
     42                 this._Listeners.BeginAcceptTcpClient(new AsyncCallback(AcceptAsync_Async), null);
     43             }
     44             catch (Exception) { }
     45         }
     46 
     47         private void AcceptAsync_Async(IAsyncResult iar)
     48         {
     49             this.AcceptAsync();
     50             try
     51             {
     52                 TcpClient client = this._Listeners.EndAcceptTcpClient(iar);
     53                 var socket = new HttpClient(client);
     54                 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());
     55                 foreach (var item in Names)
     56                 {
     57                     if (socket.http_url.StartsWith(item))
     58                     {
     59                         try
     60                         {
     61                             socket.process();
     62                             return;
     63                         }
     64                         catch { break; }
     65                     }
     66                 }
     67                 socket.WriteFailure();
     68                 socket.Close();
     69             }
     70             catch (Exception) { }
     71         }
     72 
     73         /// <summary>
     74         /// 释放资源
     75         /// </summary>
     76         public void Dispose()
     77         {
     78             if (IsInit)
     79             {
     80                 IsInit = false;
     81                 this.Dispose(true);
     82                 GC.SuppressFinalize(this);
     83             }
     84         }
     85 
     86         /// <summary>
     87         /// 释放所占用的资源
     88         /// </summary>
     89         /// <param name="flag1"></param>
     90         protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1)
     91         {
     92             if (flag1)
     93             {
     94                 if (_Listeners != null)
     95                 {
     96                     try
     97                     {
     98                         Console.WriteLine(string.Format("Stop Http Listener -> {0}:{1} ", this.IP.Address.ToString(), this.IP.Port));
     99                         _Listeners.Stop();
    100                         _Listeners = null;
    101                     }
    102                     catch { }
    103                 }
    104             }
    105         }
    106 
    107         /// <summary>
    108         /// 获取绑定终结点
    109         /// </summary>
    110         public IPEndPoint IP { get { return this._IP; } }
    111     }

    这个是实现socket监听状态

      1  public class HttpClient
      2     {
      3         private static int MAX_POST_SIZE = 10 * 1024 * 1024; // 10MB
      4         private const int BUF_SIZE = 4096;
      5         private Stream inputStream;
      6         public StreamWriter OutputStream;
      7         public String http_method;
      8         public String http_url;
      9         public String http_protocol_versionstring;
     10         public Hashtable httpHeaders = new Hashtable();
     11         internal TcpClient _Socket;
     12 
     13         /// <summary>
     14         /// 这个是服务器收到有效链接初始化
     15         /// </summary>
     16         internal HttpClient(TcpClient client)
     17         {
     18             this._Socket = client;
     19             inputStream = new BufferedStream(_Socket.GetStream());
     20             OutputStream = new StreamWriter(new BufferedStream(_Socket.GetStream()), UTF8Encoding.Default);
     21             ParseRequest();
     22         }
     23 
     24         internal void process()
     25         {
     26             try
     27             {
     28                 if (http_method.Equals("GET"))
     29                 {
     30                     Program.Pool.ActiveHttp(this, GetRequestExec());
     31                 }
     32                 else if (http_method.Equals("POST"))
     33                 {
     34                     Program.Pool.ActiveHttp(this, PostRequestExec());
     35                 }
     36             }
     37             catch (Exception e)
     38             {
     39                 Console.WriteLine("Exception: " + e.ToString());
     40                 WriteFailure();
     41             }
     42         }
     43 
     44         public void Close()
     45         {
     46             OutputStream.Flush();
     47             inputStream.Dispose();
     48             inputStream = null;
     49             OutputStream.Dispose();
     50             OutputStream = null; // bs = null;            
     51             this._Socket.Close();
     52         }
     53 
     54         #region 读取流的一行 private string ReadLine()
     55         /// <summary>
     56         /// 读取流的一行
     57         /// </summary>
     58         /// <returns></returns>
     59         private string ReadLine()
     60         {
     61             int next_char;
     62             string data = "";
     63             while (true)
     64             {
     65                 next_char = this.inputStream.ReadByte();
     66                 if (next_char == '\n') { break; }
     67                 if (next_char == '\r') { continue; }
     68                 if (next_char == -1) { Thread.Sleep(1); continue; };
     69                 data += Convert.ToChar(next_char);
     70             }
     71             return data;
     72         }
     73         #endregion
     74 
     75         #region 转化出 Request private void ParseRequest()
     76         /// <summary>
     77         /// 转化出 Request
     78         /// </summary>
     79         private void ParseRequest()
     80         {
     81             String request = ReadLine();
     82             if (request != null)
     83             {
     84                 string[] tokens = request.Split(' ');
     85                 if (tokens.Length != 3)
     86                 {
     87                     throw new Exception("invalid http request line");
     88                 }
     89                 http_method = tokens[0].ToUpper();
     90                 http_url = tokens[1];
     91                 http_protocol_versionstring = tokens[2];
     92             }
     93             String line;
     94             while ((line = ReadLine()) != null)
     95             {
     96                 if (line.Equals(""))
     97                 {
     98                     break;
     99                 }
    100                 int separator = line.IndexOf(':');
    101                 if (separator == -1)
    102                 {
    103                     throw new Exception("invalid http header line: " + line);
    104                 }
    105                 String name = line.Substring(0, separator);
    106                 int pos = separator + 1;
    107                 while ((pos < line.Length) && (line[pos] == ' '))
    108                 {
    109                     pos++;//过滤键值对的空格
    110                 }
    111                 string value = line.Substring(pos, line.Length - pos);
    112                 httpHeaders[name] = value;
    113             }
    114         }
    115         #endregion
    116 
    117         #region 读取Get数据 private Dictionary<string, string> GetRequestExec()
    118         /// <summary>
    119         /// 读取Get数据
    120         /// </summary>
    121         /// <returns></returns>
    122         private Dictionary<string, string> GetRequestExec()
    123         {
    124             Dictionary<string, string> datas = new Dictionary<string, string>();
    125             int index = http_url.IndexOf("?", 0);
    126             if (index >= 0)
    127             {
    128                 string data = http_url.Substring(index + 1);
    129                 datas = getData(data);
    130             }
    131             WriteSuccess();
    132             return datas;
    133         }
    134         #endregion
    135 
    136         #region 读取提交的数据 private void handlePOSTRequest()
    137         /// <summary>
    138         /// 读取提交的数据
    139         /// </summary>
    140         private Dictionary<string, string> PostRequestExec()
    141         {
    142             int content_len = 0;
    143             MemoryStream ms = new MemoryStream();
    144             if (this.httpHeaders.ContainsKey("Content-Length"))
    145             {
    146                 //内容的长度
    147                 content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]);
    148                 if (content_len > MAX_POST_SIZE) { throw new Exception(String.Format("POST Content-Length({0}) 对于这个简单的服务器太大", content_len)); }
    149                 byte[] buf = new byte[BUF_SIZE];
    150                 int to_read = content_len;
    151                 while (to_read > 0)
    152                 {
    153                     int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read));
    154                     if (numread == 0)
    155                     {
    156                         if (to_read == 0) { break; }
    157                         else { throw new Exception("client disconnected during post"); }
    158                     }
    159                     to_read -= numread;
    160                     ms.Write(buf, 0, numread);
    161                 }
    162                 ms.Seek(0, SeekOrigin.Begin);
    163             }
    164             WriteSuccess();
    165             StreamReader inputData = new StreamReader(ms);
    166             string data = inputData.ReadToEnd();
    167             return getData(data);
    168         }
    169         #endregion
    170 
    171         #region 输出状态
    172         /// <summary>
    173         /// 输出200状态
    174         /// </summary>
    175         public void WriteSuccess()
    176         {
    177             OutputStream.WriteLine("HTTP/1.0 200 OK");
    178             OutputStream.WriteLine("Content-Type: text/html");
    179             OutputStream.WriteLine("Connection: close");
    180             OutputStream.WriteLine("");
    181         }
    182 
    183         /// <summary>
    184         /// 输出状态404
    185         /// </summary>
    186         public void WriteFailure()
    187         {
    188             OutputStream.WriteLine("HTTP/1.0 404 File not found");
    189             OutputStream.WriteLine("Content-Type: text/html");
    190             OutputStream.WriteLine("Connection: close");
    191             OutputStream.WriteLine("");
    192         }
    193         #endregion
    194 
    195         /// <summary>
    196         /// 分析http提交数据分割
    197         /// </summary>
    198         /// <param name="rawData"></param>
    199         /// <returns></returns>
    200         private static Dictionary<string, string> getData(string rawData)
    201         {
    202             var rets = new Dictionary<string, string>();
    203             string[] rawParams = rawData.Split('&');
    204             foreach (string param in rawParams)
    205             {
    206                 string[] kvPair = param.Split('=');
    207                 string key = kvPair[0];
    208                 string value = HttpUtility.UrlDecode(kvPair[1]);
    209                 rets[key] = value;
    210             }
    211             return rets;
    212         }
    213     }

    实现了对http数据请求处理

    1 public interface ISocketPool
    2     {
    3         /// <summary>
    4         /// 
    5         /// </summary>
    6         /// <param name="client"></param>
    7         void ActiveHttp(Fly.Network.SocketPool.Http.HttpClient client, Dictionary<string, string> parms);
    8     }
     1 public class Program
     2     {
     3         public static MessagePool Pool = new MessagePool();
     4         static void Main(string[] args)
     5         {
     6             HttpServer https = new HttpServer("127.0.0.1", 80, new HashSet<string>() {"/test/","/flie/" });
     7             Console.ReadLine();
     8         }
     9     }
    10     class MessagePool : ISocketPool
    11     {
    12         public void ActiveHttp(HttpClient client, Dictionary<string, string> parms)
    13         {
    14             Thread.Sleep(new Random().Next(0, 3000));
    15             foreach (var item in parms)
    16             {
    17                 Console.WriteLine(DateTime.Now.NowString() + "item.Key:" + item.Key + "; item.Value:" + item.Value);
    18             }
    19             string strHtml = @"
    20 <html><head></head>
    21 <body>
    22 <div>&nbsp;</div>
    23 <div>&nbsp;</div>
    24 <div>&nbsp;</div>
    25 <div>&nbsp;</div>
    26 <div>&nbsp;</div>
    27 {0}
    28 </body>
    29 </html>
    30 ";
    31             client.OutputStream.WriteLine(string.Format(strHtml, DateTime.Now.NowString() + "xxxxxxxxxxx"));
    32             client.Close();
    33         }
    34     }

    程序启动过后,看到输出

    2015-04-13 16:23:21:059:Start Listen Http Socket -> 127.0.0.1:80/test/
    2015-04-13 16:23:21:069:Start Listen Http Socket -> 127.0.0.1:80/flie/

    接下来我们在浏览器输入 127.0.0.1/test/

    正常收到请求,输出程序

    127.0.0.1/test/

    这里test1这个并不是我们监听饿目录,根本不会处理,

    接下来我们再看看这个效果 get提交的参数 127.0.0.1/test/?bb=test

    输出了get提交过来的参数信息。可能你会奇怪,为什么一次请求会收到两次连接请求。这里我查看过了其中一次请求是浏览器自带的请求页面标签的icon连接请求,

    如果你拷贝了程序,你现在可以实现跑来程序,然后输入网址,按着F5不放,看看服务器的承受能力,当然这里忽律了逻辑方面对cpu内存消耗和时间消耗问题。

    测试看看吧。

    跪求保留标示符
    /**
     * @author: Troy.Chen(失足程序员, 15388152619)
     * @version: 2021-07-20 10:55
     **/
    
    C#版本代码 vs2010及以上工具可以
    
    java 开发工具是netbeans 和 idea 版本,只有项目导入如果出现异常,请根据自己的工具调整
    
    
    提供免费仓储。
    最新的代码地址:↓↓↓
    https://gitee.com/wuxindao
    
    觉得我还可以,打赏一下吧,你的肯定是我努力的最大动力
        
    
  • 相关阅读:
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现业务
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 开发流程
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 报表系统集成说明
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 处理报表
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据访问
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 分布式应用
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 实现插件
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 对象设计器使用帮助
    基于DotNet构件技术的企业级敏捷软件开发平台 AgileEAS.NET平台开发指南 数据层开发
    Jquery 中的CheckBox、 RadioButton、 DropDownList、CheckBoxList、RadioButtonList的取值赋值
  • 原文地址:https://www.cnblogs.com/shizuchengxuyuan/p/4422544.html
Copyright © 2011-2022 走看看