C# 利用socekt做到http监听,怎么样才能做到高性能
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内存消耗和时间消耗问题。
测试看看吧。
C# 利用socekt做到http监听,怎么样才能做到高性能的更多相关文章
- 利用Node的chokidar 监听文件改变的文件。
最近维护一个项目.每次改完东西,都要上传到服务器.然后有时候就忘记一些东西,于是就想有没有可以方法能监听文件的改变.然后我再利用程序把更改的文件一键上传到服务器. 于是就找到了nodejs 的chok ...
- 利用spring的ApplicationListener监听某一类事件的发生
1.ApplicationListener在使用过程中可以监听某一事件的发生,可以做出相应的处理,这个方式不常用,但是在特殊情况下面还是有用的. 2.导包pom.xml <project xml ...
- android菜鸟学习笔记23----ContentProvider(三)利用内置ContentProvider监听短信及查看联系人
要使用一个ContentProvider,必须要知道的是它所能匹配的Uri及其数据存储的表的结构. 首先想办法找到访问短信及联系人数据的ContentProvider能接受的Uri: 到github上 ...
- 利用input事件来监听移动端的输入
今天遇到一个新需求,经理要求评论功能需要限制字数,就像微博那样限制最多输入150字,这里就需要实时提醒用户还能输入多少字了. 在最开始的时候,想到的是监听keyup事件,然后计算用户输入的字数,但是有 ...
- 利用bootstrap制作滚动监听
滚动监听(Scrollspy)插件,即自动更新导航插件,会根据滚动条的位置自动更新对应的导航目标. 在这里,需要引入三个文件:bootstrap.min.css jquery-3.3.1.j ...
- 20180530利用Maxwell组件实时监听Mysql的binlog日志
转自:https://blog.csdn.net/qq_30921461/article/details/78320750 http://kafka.apache.org/quickstart htt ...
- 利用input event 实时监听input输入的内容
<div id="addNumber"> <p>How many people would you like to invite?</p> &l ...
- 利用原生JS实时监听input框输入值
传送门https://www.cnblogs.com/lantinggumo/p/7636715.html 传送门https://www.cnblogs.com/nailc/p/8572226.htm ...
- Android监听手机网络变化
Android监听手机网络变化 手机网络状态发生变化会发送广播,利用广播接收者,监听手机网络变化 效果图 注册广播接收者 <?xml version="1.0" encodi ...
随机推荐
- NSTimer整理总结
对于定时器NSTimer,我们大家都不会陌生,在使用的时候,我们常常会遇到一些坑,例如:在Scrollview拖动时,timer会暂停:在子线程中如何创建一个定时器等.针对于一些我们所遇到的坑,我来总 ...
- TestNG 与 Junit的比较
转自 http://www.blogjava.net/fanscial/archive/2005/12/14/23780.html 1. JDK 5 Annotations (JDK ...
- java读写Properties属性文件公用方法
Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件. 它提供了几个主要的方法: 1. getProperty ( String ...
- Jquery 仿 android Toast效果
JS代码如下: /** * 模仿android里面的Toast效果,主要是用于在不打断程序正常执行的情况下显示提示数据 * @param config * @return */var Toast = ...
- 你必须知道的Javascript 系列
JavaScript是见过最多人说它“有趣”,“好玩”的一门语言.不仅仅是因为它的灵活性,包括它本身很多的特性,比如说原型链,作用域链都是非常好玩的东西.现在已经有很多的JavaScript设计模式, ...
- .net中事件引起的内存泄漏分析
系列主题:基于消息的软件架构模型演变 在Winform和Asp.net时代,事件被大量的应用在UI和后台交互的代码中.看下面的代码: private void BindEvent() { var bt ...
- Backbone源码分析(一)
距离上一篇博客有一段时间了,期间各种琐事萦绕.最主要的一件是,当我差不多将整个dojo核心源码看完,惊讶的发现dojo1.*的设计以是老态龙钟之象,而我沉溺在dojo中太久,已经不知道前端世界变成了什 ...
- 顶级的JavaScript框架、库、工具及其使用
几乎每隔一个星期,就有一个新的 JavaScript 库席卷网络社区!Web 社区日益活跃.多样,并在多个领域快速成长.想要研究每一个重要的 JavaScript 框架和库,是个不可能完成的任务.接下 ...
- TODO:Golang Linux进程退出说明
TODO:Golang Linux进程退出说明 Golang使用os.Exit(code)进程退出导致当前程序退出并返回给定的状态代码.传统上,code代码为零表示成功退出,非零错误退出. sysca ...
- TODO:小程序手机预览调试
TODO:小程序手机预览调试 1. 小程序注册,目前还未开通个人注册,主体类型为企业.政府.媒体.其他组织 2. 登录小程序,绑定开发者,获取AppID 3. 下载微信小程序示例-新片预告 https ...