【问题标题】:Thread-safe server线程安全服务器
【发布时间】:2014-11-15 23:30:38
【问题描述】:

我尝试实现多线程服务器。很少有客户端(PUT 请求)。在GET 服务器上必须发送包含此数据的集合。这是我的服务器代码:

class Server
{
    private HttpListener httpListener;
    private static System.Threading.AutoResetEvent listenForNextRequest = new System.Threading.AutoResetEvent(false);
    public static BlockingCollection<NodeInfo> locations = new BlockingCollection<NodeInfo>();

    public Server()
    {
        const string ip = "127.0.0.1";
        const int port = 9999;
        string prefix = String.Format("http://{0}:{1}/", ip, port.ToString());

        httpListener = new HttpListener();
        httpListener.Prefixes.Clear();
        httpListener.Prefixes.Add(prefix);

        Console.WriteLine("HTTP server is running ...");
        Console.WriteLine("Listening on {0} ...\n", prefix);
    }

    public void Start()
    {
        httpListener.Start();
        ThreadPool.SetMaxThreads(10, 10);
        ThreadPool.QueueUserWorkItem(new WaitCallback(Listen));
        Thread.Sleep(7000);
    }

    internal void Stop()
    {
        httpListener.Stop();
    }

    private void Listen(object state)
    {
        while (httpListener.IsListening)
        {
            httpListener.BeginGetContext(new AsyncCallback(ListenerCallback), httpListener);
            listenForNextRequest.WaitOne();
        }
    }

    private static void ListenerCallback(IAsyncResult result)
    {
        HttpListener listener = (HttpListener)result.AsyncState;

        // Request
        HttpListenerContext context = listener.EndGetContext(result);

        if (context.Request.HttpMethod.Equals("PUT"))
        {
            PutRequestProcess(context);
        }

        if (context.Request.HttpMethod.Equals("GET"))
        {
            GetRequestProcess(context);
        }

        // Process next request
        result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
    }

    private static void PutRequestProcess(HttpListenerContext context)
    {
        // Request object
        HttpListenerRequest request = context.Request;

        using (Stream stream = request.InputStream)
        {
            // Deserialize
            DataContractSerializer ser = new DataContractSerializer(typeof(NodeInfo));
            XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());

            // Deserialize the data and read it from the instance.
            NodeInfo nodeInfo = (NodeInfo)ser.ReadObject(reader, true);
            reader.Close();
            stream.Close();

            locations.Add(nodeInfo);
        }

        // Response object
        HttpListenerResponse response = context.Response;

        response.StatusCode = (int)HttpStatusCode.OK;

        using (Stream stream = response.OutputStream)
        {
            stream.Close();
        }
    }

    private static void GetRequestProcess(HttpListenerContext context)
    {
        // Response object
        HttpListenerResponse response = context.Response;

        response.StatusCode = (int)HttpStatusCode.OK;

        using (Stream stream = response.OutputStream)
        using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream))
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(List<NodeInfo>));
            {
                writer.WriteStartDocument();
                ser.WriteObject(writer, locations.ToList());
            }

            stream.Close();
        }
    }
}

PUT 请求似乎有效。但是当我尝试接收这个集合(GET 请求)时,我在反序列化时遇到了一个异常:Unexpected end of file... 在调试器中,XML 字符串的末尾并非所有标签。我认为写线程(服务器)没有完成。我该如何解决? 我也有几个问题。这个实现是线程安全的吗?如果我使用并发集合,我不需要使用信号量或其他同步?

非常感谢!

【问题讨论】:

  • 您对实现 WCF 服务或 ASP.NET Web API 有任何限制吗?因为这些框架会抽象出很多东西,比如连接管理和线程同步,让你的生活更轻松:)
  • Thomas C. G. de Vilhena,是的,我需要使用 HttpListener calss 来实现它。 WCF 不允许

标签: c# asynchronous httpclient


【解决方案1】:

您似乎过早地关闭了输出流。在GetRequestProcess() 中,只需删除对stream.Close() 的调用即可。这将让编写器在关闭时刷新到流。只要您正确处理对象(就像您在此处显示的那样),您就不需要显式关闭任何东西。

至于您的其他问题,如果您在使线程安全工作时遇到特定问题,我建议您发布一个不同的问题,不要使用所有 I/O 代码来混淆事物。如果您只是希望有人审查您的代码,请使用 Stack Exchange 上的代码审查网站。

【讨论】:

    猜你喜欢
    • 2014-06-14
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多