请问园子中的各位大佬们,如果使用HttpListener如何开发一款支持异步的web服务器,如果大佬们有github上的现成的例子的话,恳请甩上一下,供小弟拜读一番,自己也做了一下,如果大佬们有时间的话还请斧正.
这款异步web服务器主要用来对接CoolQ HTTP API,接收上报的请求并托管到自己的程序进行处理,下面粘贴一下小弟的拙作,还请斧正https://github.com/f472918106/FlyingCube/blob/master/FlyingCube/Service/AsyncHttpService.cs
1 /// <summary> 2 /// 开始监听,将消息加入消息队列 3 /// </summary> 4 /// <returns></returns> 5 public async Task Start() 6 { 7 listener.Start(); 8 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 开始监听"+ServiceUrl+"\n"; 9 while (true) 10 { 11 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 监听中... \n"; 12 var context = await listener.GetContextAsync(); 13 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 接收到一条新的请求... \n"; 14 await ReportContext(context); 15 await ReturnResponse(context); 16 } 17 } 18 19 /// <summary> 20 /// 停止监听 21 /// </summary> 22 /// <returns></returns> 23 public async Task Stop() 24 { 25 listener.Stop(); 26 await Task.Delay(TimeSpan.FromSeconds(2)); 27 } 28 29 /// <summary> 30 /// 异步上报HttpListentContext实体 31 /// </summary> 32 /// <param name="context">HttpListentContext实体</param> 33 /// <returns></returns> 34 private async Task ReportContext(HttpListenerContext context) 35 { 36 StreamReader reader = new StreamReader(context.Request.InputStream); 37 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 正在读取请求... \n"; 38 string request = await reader.ReadToEndAsync(); 39 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 请求读取完成,内容如下: \n"+request+"\n"; 40 reader.Close(); 41 MsgQueue.Enqueue(request); 42 current.richTextBox_MsgQueue.Text += "[" + DateTime.Now + "] 已加入消息队列. \n"; 43 await AsyncTaskService.TaskEnqueue(request); 44 }
目前使用的是HttpListener.GetContextAsync()方法,之前也尝试过用HttpListener.BeginGetContext通过回调函数递归调用当前函数,来实现循环监听,但是由于眼拙,没有看出明显的异步操作特点,就改用了HttpListener.GetContextAsync(),现在实现的效果就是同一秒可以接收多条请求并创建相应作业加入作业队列,但是感觉还是有些怪怪的,小弟愚笨,还请各位大佬提点提点,除此之外还有一个小问题,就是async和await,当出现await以后具体程序是怎么执行的,emmmmm,看了很多大佬的帖子,自己也单步运行测试了很多次还是没有确定await出现以后究竟发生了什么,在此小弟先行谢过各位大佬!!!
Task await 是非常复杂的一个机制,await编译器会生成一个状态机,这个状态机使用yield构成了一个协程操作,协程有自己的上下文,保存有内部变量,在协程生存期是随时可以访问的
在Task的内部实现,也不是新开一个线程去执行那么简单,通过系统底层api,加上TaskCompletionSource来异步通知任务状态的完成
clr方面,Task的协程调度,信号传送和激活下一个任务,这些都是clr支持的
所以这个机制很复杂,很少有人说得清楚,最近我正准备从上而下,分析corefx,coreclr源码来找到答案
在异步服务器方面,可以参考kestrel的思想,了解socket到底怎么利用native api实现异步操作的
好的,谢谢大佬,等大佬分析出来,回去围观学习的~~
歇歇吧,新手用用框架就差不多了,如果是学习你完全可以从tcp写着玩,能更多的了解一点通讯和http。
就是做着玩的,只想用HttpListener,学过网原,玩玩而已,socket反向,udp,tcp以前写过一点基本的了,我只是为了对接CoolQ Http Api,消息上报方式是http或websocket反向代理,想问问大佬难道我该用tcp去对接?其实也想用asp.net core来处理,但是能力有限,还没有理解asp.net core如何把监听的事件上报到指定程序
@慕平生: 你的场景不甚清楚。有不少时候从tcp层写调用比http写更方便且更准确。给你建议tcp是因为那样可以让你更清楚的知道http的长相。 websocket 相对麻烦一些。都可以自己通过tcp来easy实现 ,达到更深刻的理解,也能使自己对实际http等系统参数设置有理解,做到更安全等等。
@花飘水流兮: 好的,谢谢大佬,具体应用场景主要就是https://github.com/richardchien/coolq-http-api这个项目,其实也是出于兴趣做着玩的,主要是想通过这个api来实现一些关于NLP的学习,小弟对c#异步理解的很模糊,不知道大佬有没有比较好的相关文章推荐,还有就是如果可以的话,大佬是否可以推荐一些关于使用asp.net core内置的Kestrel基础配置和处理http请求机制的文章,其实自己也查了很多,但是由于小弟愚笨,都是一知半解,不会实际应用,也想使用框架来处理,但是见识短浅,只知道kestrel,emmmmm,而且看官方文档也还是只停留在知道怎么配置使用kestrel来监听,但是不理解具体机制,不知道改如何或者说从哪里读取这个请求,httplistener也是不得己而为之
虽然是做着玩,但也要认真的去玩!玩出整个知识体系来
现在对kestrel分析的文章不多,最好能找到源码分析的文章,这样你就可以从中学习到源码分析的技巧以及kestrel的设计思想
在拥抱开源的这个时代,我觉得源码分析能力能够帮助大部分c#程序员更进一步的必要手段
@幻影gool: 好的,谢谢大佬的建议!