我正在为C#中的教育目的编写嵌入式HTTP服务器(更多地了解rfc并学习有关winsock的内容)。
现在我可以提供静态网页。服务器本身看起来很合理,有一个很好的例外。与IE相比,Chrome加载我的测试页面的速度非常慢。此外,捕获的网络日志显示每个请求的延迟很长。
Web服务器和浏览器在同一台计算机上运行,因此应尽量减少网络延迟。
我查看了其他.NET HTTP服务器实现。使用HttpListener的实现没有显示此行为。我发现的套接字实现和我的实现一样慢。 目前我试图找出为什么Chrome与其他浏览器的行为如此不同以及为什么HttpListener不会受此影响(我知道HttpListener使用HTTP API 2.0但我不知道这个API本身是否使用winsock或其他东西)。
我会附上重要的代码来接受,阅读和回复单个请求,以及IE和Chrome的网络日志。
我接受新套接字的当前代码是:
socket.Listen(10);
IAsyncResult asyncResult = null;
while (!token.IsCancellationRequested)
{
if (asyncResult == null)
asyncResult = socket.BeginAccept(null, null);
if (asyncResult.IsCompleted)
{
var acceptedSocket = socket.EndAccept(asyncResult);
var connection = new HttpServerConnection(acceptedSocket);
var queue = this.queue;
queue.Enqueue(connection);
asyncResult = null;
}
else
{
Thread.Sleep(5);
}
}
接受套接字的队列由另一个后台线程处理。监听器等待,直到使用socket.Poll(1000, SelectMode.SelectRead);
从套接字读取数据(因为Chrome打开多个连接到HTTP服务器,理论上加速页面加载)。
在服务器处理请求之后,使用以下命令发送响应:
var response = context.Response;
var connection = context.Connection;
byte[] buffer;
using (var stream = new MemoryStream(1024))
{
using (var writer = new StreamWriter(stream, Encoding.ASCII, 1024, true))
{
writer.Write(HttpVersion.Http11.ToString());
writer.Write(" ");
writer.Write((int)response.Status);
writer.Write(" ");
writer.WriteLine(response.StatusDescription ?? response.Status.ToString());
foreach (var httpHeader in response.Headers)
{
writer.Write(httpHeader.Key);
writer.Write(": ");
writer.WriteLine(httpHeader.Value());
}
if (response.Content != null)
writer.WriteLine();
}
if (response.Content != null)
response.Content(context, stream);
stream.Position = 0;
buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
}
connection.Send(buffer);
IE首页加载,包括捕获的netword和服务器日志记录:
如您所见,除了第一个请求(因为请求解析器和管道在第一次使用时已初始化),处理速度足够快。 IE在16ms内收到回复。
现在Chrome首页加载:
服务器处理响应的速度与来自IE的响应一样快,但每次请求Chrome需要大约300毫秒。
编辑:HTML页面的请求/响应(第一个HTTP请求)
非常感谢有这种行为和解决问题的可能性的任何线索!
经过一些研究后,我发现了这种行为的原因。不知何故,Chrome需要更长的时间来从环回适配器的主机文件中解析主机名。使用IP地址而不是“localhost”会在10ms内产生可接受的响应。 如果使用HttpListener,则不会发生此行为的原因是HttpListener使用HTTP API创建UrlGroups以将URI与底层套接字映射。
答案 0 :(得分:0)
经过一些研究后,我发现了这种行为的原因。不知何故,Chrome需要更长的时间来从环回适配器的主机文件中解析主机名。使用IP地址而不是“localhost”会在10ms内产生可接受的响应。 如果使用HttpListener,则不会发生此行为的原因是HttpListener使用HTTP API创建UrlGroups以将URI与底层套接字映射。