Web Server - различни решения
Сървърът от лаба и Handmade сървърът НЕ работят асинхронно -поне при мен.
Тествам с Firefox Developer Edition има измерване на времето за отговор.
Това е кода от лекцията, по същият начин е на презентацията. Така е и на предната инстанция.
На презентацията слагат Task.Wait() в Main - така се блокира приложението и изобщо сърърът не може друго да прави
( например Console.ReadLine();)
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
public class Program
{
static void Main(string[] args)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
int port = 8081;
TcpListener tcpListener = new TcpListener(address, port);
tcpListener.Start();
Console.WriteLine($"Listening to TCP clients at 127.0.0.1:{port}");
Task.Run(async () => await Connect(tcpListener));
Console.ReadLine();
}
public static async Task Connect(TcpListener tcpListener)
{
Console.WriteLine("Waiting for client...");
while (true)
{
TcpClient client = await tcpListener.AcceptTcpClientAsync();
Console.WriteLine("Client connected.\n");
byte[] buffer = new byte[1024];
await client.GetStream().ReadAsync(buffer, 0, buffer.Length);
string message = Encoding.ASCII.GetString(buffer);
Console.WriteLine(message);
byte[] response = Encoding.ASCII.GetBytes("<body><h1>Hello from server!</h1></body>");
await Task.Delay(5000);
await client.GetStream().WriteAsync(response, 0, response.Length);
Console.WriteLine("Closing connection");
client.GetStream().Dispose();
}
}
}
Полезно обяснение за async await. http://zpbappi.com/using-csharp-async-and-await-properly/
Така и не успях да го подкарам асинхронно.
От тук взех сървър, който работи асинхронно и използва HttpListener.
Добавих Delay за 5 сек. и като пусна няколко заявки всички минават за 5 секунди, а не се изчакват.
using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace HttpServer
{
public static class Server
{
public static int maxSimultaneousConnections = 20;
private static Semaphore sem = new Semaphore(maxSimultaneousConnections, maxSimultaneousConnections);
private static HttpListener InitializeListener()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://127.0.0.1:8081/");
Console.WriteLine("Listening on IP 127.0.0.1:8081");
return listener;
}
private static void StartListener(HttpListener listener)
{
listener.Start();
Task.Run(() => RunServer(listener));
}
public static void Start()
{
HttpListener listener = InitializeListener();
StartListener(listener);
}
private static void RunServer(HttpListener listener)
{
while (true)
{
sem.WaitOne();
StartConnectionListener(listener);
}
}
private static async void StartConnectionListener(HttpListener listener)
{
// Wait for a connection. Return to caller while we wait.
HttpListenerContext context = await listener.GetContextAsync();
// Release the semaphore so that another listener can be immediately started up.
sem.Release();
// We have a connection, do something...
string response = "Hello Browser!";
byte[] encoded = Encoding.UTF8.GetBytes(response);
context.Response.ContentLength64 = encoded.Length;
await Task.Delay(5000);
context.Response.OutputStream.Write(encoded, 0, encoded.Length);
context.Response.OutputStream.Close();
}
}
}
След дълго ровене в нета за C# Web Server излиза, че се реализира основно с TCPListener и по-рядко с HTTPListener.
Предимства на HttpListener: HttpListener парсва HTTP хедърите и създава HTTP респонси.
Дава набор от класове, които са много подобни на тези в ASP.Net, които дават достъп до хедъри, кукита и други.
Основен недостатък на HttpListener - когато клиентът и сървърът са на една машина производителността пада при изпращане на съобщения с голям размер на бодито.