【发布时间】:2014-12-20 07:44:37
【问题描述】:
我是 winservice 开发的新手。我需要创建一个服务,它将包含一些函数和 api:当一些请求到来时它应该做一些事情。
据我了解,我需要使用 HttpListener 类。
这里描述了这个问题的基础:How to create a HTTP request listener Windows Service in .NET 但它还没有完成代码,我还有更多问题。
这是我的代码:
partial class MyService
{
private System.ComponentModel.IContainer components = null;
private System.Diagnostics.EventLog eventLog1;
private HttpListener listener;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.eventLog1 = new System.Diagnostics.EventLog();
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).BeginInit();
this.ServiceName = Globals.ServiceName;
((System.ComponentModel.ISupportInitialize)(this.eventLog1)).EndInit();
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:1111/");
listener.Start();
listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
}
}
public partial class MyService : ServiceBase
{
public MyService()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource(
"MySource", "MyNewLog");
}
eventLog1.Source = "MySource";
eventLog1.Log = "MyNewLog";
}
// smth about onstart and onstop
private void OnRequestReceive(IAsyncResult result)
{
eventLog1.WriteEntry("Connection catched!");
HttpListener listener = (HttpListener)result.AsyncState;
eventLog1.WriteEntry("1");
HttpListenerContext context = listener.GetContext();
eventLog1.WriteEntry("2");
HttpListenerRequest request = context.Request;
eventLog1.WriteEntry("3");
HttpListenerResponse response = context.Response;
eventLog1.WriteEntry("4");
string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}
}
所以,我添加了一些日志来了解发生了什么:
当我重新安装并启动服务时,我打开 http://localhost:1111/ 并
- 有时一切正常,我在浏览器中看到 HelloWorld,在 MyLog 中看到 1234
- 有时它卡住了,我等待,等待,等待。那时我可以在日志中看到“1”,但看不到“2”。如果我只是等待,什么都不会发生。但是,如果我再次加载 localhost(或按 f5),我可以看到 Hello World... 而日志只是添加了 234,它是 1234 而不是 11234 总结..
在那之后,它只是卡住了,在我重新启动服务之前,日志中没有任何变化。
所以,我明白了,这个问题可能出在listener.EndGetContext,尚未使用。
我在代码中测试了这个变化(最后两行):
private void OnRequestReceive(IAsyncResult result)
{
eventLog1.WriteEntry("Connection catched!");
HttpListener listener = (HttpListener)result.AsyncState;
eventLog1.WriteEntry("1");
HttpListenerContext context = listener.GetContext();
eventLog1.WriteEntry("2");
HttpListenerRequest request = context.Request;
eventLog1.WriteEntry("3");
HttpListenerResponse response = context.Response;
eventLog1.WriteEntry("4");
string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
listener.EndGetContext(result);
listener.BeginGetContext(new AsyncCallback(OnRequestReceive), listener);
}
这个糟糕的代码有效:当显示 HelloWorld 时,我可以重新加载页面并再次查看它(并且日志多次显示 1234)。但是我仍然对 1......234 有问题(对于某些加载的 HelloWorld 会出现,对于有些则不会)
当然,在回调结束时使用 BeginGetContext 是很糟糕的,但这只是我的测试。
另外,我需要处理并行请求
那么,如何以正确的方式做到这一点?我找不到任何关于在 google 中接收 winservices 请求的有用信息。只是关于 HttpListener 的问题 ..
更新:
我尝试了新方法:
HttpListener listener = new HttpListener();
listener.Prefixes.Add(Globals.URL);
listener.Start();
listenerThread = new Thread(() =>
{
while (listener.IsListening)
{
HandleRequest(listener.GetContext());
}
});
listenerThread.Start();
一切正常,当上下文出现时它会等待,使用它并再次等待。但是这种方式会创建一个请求队列。如果一次有1000个请求,最后一个会在999之后处理。总比没有好,但我想并行处理请求。此外,发生了非常奇怪的事情:我创建了带有一些路由的简单网络服务器,但使用一段时间后,它挂起。在我重新安装(不是重新启动!)服务之前没有任何变化。
所以,我仍在等待任何真正好的实现,它将包含
- 并行处理传入请求
- 用于理解回调等的清晰简单的代码
- 停止服务不会对 while 循环造成任何问题
【问题讨论】:
标签: http windows-services httplistener