我在c#.NET中实现了一个HTTP服务器:
public class HttpServer
{
private HttpListener listener;
public HttpServer()
{
listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
}
public void Start()
{
lock(this) {
listener.Start();
AsyncProcessing(listener);
}
}
public void Stop()
{
lock (this) {
listener.Stop();
}
}
private void AsyncProcessing(HttpListener listener)
{
if (listener == null)
return;
listener.BeginGetContext(new AsyncCallback(Callback), listener);
}
private void Callback(IAsyncResult result)
{
HttpListenerContext context = null;
lock(this) {
HttpListener listener = (HttpListener)result.AsyncState;
if (!listener.IsListening)
return;
context = listener.EndGetContext(result);
AsyncProcessing(listener);
}
/* handle request */
}
}
我对此实施有一些疑问:
感谢您的想法
答案 0 :(得分:4)
请记住,我不是多线程的专家,所以你应该尽可能地保证我所说的任何事情。
如果其他人知道,并且只想窃取我的整个答案,只是编辑或更正细节,请随时执行此操作。
让我们一个一个地处理你的问题:
我在这里和那里添加了一些锁以防止竞争条件,但我很困惑:那些真的需要吗?我在文档中读到所有公共非静态方法都不是线程安全的。为什么我没有看到考虑这个事实的代码?
嗯,是的,不是。锁通常用于防止多个线程同时访问同一数据结构,因为它会破坏数据结构。考虑在一个线程上对数组进行排序,在另一个线程中插入一个元素,将这两个线程正确计时会破坏数组的内容。
现在,在您的代码中,您锁定this
,这绝不是一个好主意。外部代码可能也会对同一个对象进行锁定,这是您无法控制的,所以为了创建生产就绪代码,我不会这样做。< / p>
如果你的代码中需要锁,我会构造特定的锁对象并使用它们。
换句话说,添加:
private readonly object _Lock = new object();
然后您的所有地方lock(this)
将其替换为lock(_Lock)
。这样,如果需要,您还可以拥有多个锁。
至于实际需要锁,我不是100%肯定。我不确定的事情是你在调用Stop之前锁定,并且你锁定了回调并在锁内部检查了监听器是否仍在运行。
这将阻止您在接受请求后但在实际处理请求之前停止侦听器。换句话说,听起来你会阻止关闭服务器,同时仍然处理打开的请求。
但是,不,你不会阻止它,因为你可能会在回调中离开锁定部分后停止服务器,但是在评论代码完全执行期间或之前,所以你仍然会遇到这个问题。
然而这也意味着您已经有效地序列化了一些回调方法,即调用EndGetContext并重新启动BeginGetContext循环的部分。不管这是不是好的模式,我不知道。
HttpListenerContext的行为如何?他与HttpListener有某种联系吗?或者我可以同时使用多个HttpListenerContexts吗?
我会猜测一下。该类没有引用回侦听器类或,它具有与之协作的线程安全方式。
如果必须序列化对请求/响应数据的每次访问,那么基于线程的http侦听器系统就不会太多了。
在任何情况下,如果有疑问,请检查您正在访问的上下文类的方法和/或属性的文档,如果您需要采取措施来确保线程安全,文档将会这样说。 / p>
我听说HttpListener不会为生产系统做好准备,但我从未见过支持这种说法的论据。这是真的吗?
(见问题评论)
还有其他我应该考虑的事情吗?
多线程代码很难来编写。从你的问题来看,我猜想你没有做过很多事情,说实话,虽然我已经做了很多,但我还是觉得自己处于昙花一现。
我的建议如下: