Потокобезопасный сервер

1

Я пытаюсь реализовать многопоточный сервер. Немногие клиенты (<10) отправят некоторые данные на сервер (запрос 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. Я думаю, что писать нить (сервер) не заканчивается. Как я могу это исправить? Также у меня мало вопросов. Является ли эта реализация поточно-безопасной? Если я использую параллельные коллекции, мне не нужно использовать семафор или другую синхронизацию?

Большое спасибо!

  • 0
    Есть ли у вас какие-либо ограничения на реализацию службы WCF или ASP.NET Web API? Потому что эти структуры будут абстрагироваться от множества вещей, таких как управление соединениями и синхронизация потоков, что сделает вашу жизнь намного проще :)
  • 0
    Thomas CG de Vilhena, да, мне нужно реализовать это, используя HttpListener HttpListener calss. WCF не допускается
Теги:
httpclient
asynchronous

1 ответ

1
Лучший ответ

Похоже, вы закрываете выходной поток преждевременно. В GetRequestProcess() просто удалите этот вызов для stream.Close(). Это позволит автору приступить к потоку, когда он закрыт. Вам не нужно явно закрывать что-либо, пока вы правильно распоряжаетесь объектами (как вы, кажется, здесь).

Что касается остальных ваших вопросов, я рекомендую вам задать другой вопрос, без всякого кода ввода/вывода, чтобы запутать вещи, если у вас возникли определенные проблемы с обеспечением безопасности потоков. Если вы просто хотите, чтобы кто-то просмотрел ваш код, используйте сайт Code Review на Stack Exchange.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню