生产就绪,多线程c#http服务器

时间:2011-06-16 12:24:35

标签: c# httplistener

我在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 */
    }
}

我对此实施有一些疑问:

  • 我在这里和那里添加了一些锁以防止竞争条件,但我很困惑:那些真的需要吗?我在文档中读到所有公共非静态方法都不是线程安全的。为什么我没有看到考虑这个事实的代码?
  • HttpListenerContext的行为如何?他与HttpListener有某种联系吗?或者我可以同时使用多个HttpListenerContexts吗?
  • 我听说HttpListener不会为生产系统做好准备,但我从未见过支持这种说法的论据。这是真的吗?
  • 还有其他我应该考虑的事项吗?

感谢您的想法

1 个答案:

答案 0 :(得分:4)

请记住,我不是多线程的专家,所以你应该尽可能地保证我所说的任何事情。

如果其他人知道,并且只想窃取我的整个答案,只是编辑或更正细节,请随时执行此操作。

让我们一个一个地处理你的问题:

  

我在这里和那里添加了一些锁以防止竞争条件,但我很困惑:那些真的需要吗?我在文档中读到所有公共非静态方法都不是线程安全的。为什么我没有看到考虑这个事实的代码?

嗯,是的,不是。锁通常用于防止多个线程同时访问同一数据结构,因为它会破坏数据结构。考虑在一个线程上对数组进行排序,在另一个线程中插入一个元素,将这两个线程正确计时会破坏数组的内容。

现在,在您的代码中,您锁定this,这绝不是一个好主意。外部代码可能也会对同一个对象进行锁定,这是您无法控制的,所以为了创建生产就绪代码,我不会这样做。< / p>

如果你的代码中需要锁,我会构造特定的锁对象并使用它们。

换句话说,添加:

private readonly object _Lock = new object();

然后您的所有地方lock(this)将其替换为lock(_Lock)。这样,如果需要,您还可以拥有多个锁。

至于实际需要锁,我不是100%肯定。我不确定的事情是你在调用Stop之前锁定,并且你锁定了回调并在锁内部检查了监听器是否仍在运行。

这将阻止您在接受请求后但在实际处理请求之前停止侦听器。换句话说,听起来你会阻止关闭服务器,同时仍然处理打开的请求。

但是,不,你不会阻止它,因为你可能会在回调中离开锁定部分后停止服务器,但是在评论代码完全执行期间或之前,所以你仍然会遇到这个问题。

然而这也意味着您已经有效地序列化了一些回调方法,即调用EndGetContext并重新启动BeginGetContext循环的部分。不管这是不是好的模式,我不知道。

  

HttpListenerContext的行为如何?他与HttpListener有某种联系吗?或者我可以同时使用多个HttpListenerContexts吗?

我会猜测一下。该类没有引用回侦听器类,它具有与之协作的线程安全方式。

如果必须序列化对请求/响应数据的每次访问,那么基于线程的http侦听器系统就不会太多了。

在任何情况下,如果有疑问,请检查您正在访问的上下文类的方法和/或属性的文档,如果您需要采取措施来确保线程安全,文档将会这样说。 / p>

  

我听说HttpListener不会为生产系统做好准备,但我从未见过支持这种说法的论据。这是真的吗?

(见问题评论)

  

还有其他我应该考虑的事情吗?

多线程代码很难来编写。从你的问题来看,我猜想你没有做过很多事情,说实话,虽然我已经做了很多,但我还是觉得自己处于昙花一现。

我的建议如下:

  • 真的需要多线程吗?
  • 您是否有其他同事可以帮助您了解更多信息?