Я пытаюсь реализовать многопоточный сервер. Немногие клиенты (<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
. Я думаю, что писать нить (сервер) не заканчивается. Как я могу это исправить? Также у меня мало вопросов. Является ли эта реализация поточно-безопасной? Если я использую параллельные коллекции, мне не нужно использовать семафор или другую синхронизацию?
Большое спасибо!
Похоже, вы закрываете выходной поток преждевременно. В GetRequestProcess()
просто удалите этот вызов для stream.Close()
. Это позволит автору приступить к потоку, когда он закрыт. Вам не нужно явно закрывать что-либо, пока вы правильно распоряжаетесь объектами (как вы, кажется, здесь).
Что касается остальных ваших вопросов, я рекомендую вам задать другой вопрос, без всякого кода ввода/вывода, чтобы запутать вещи, если у вас возникли определенные проблемы с обеспечением безопасности потоков. Если вы просто хотите, чтобы кто-то просмотрел ваш код, используйте сайт Code Review на Stack Exchange.
HttpListener
HttpListener calss.WCF
не допускается