问题概述:我一直在玩编写自定义http服务器应用程序一段时间。我发现,当任何连接到我的服务器应用程序的网络浏览器,将有一个0.5-1秒的“延迟”(根据谷歌浏览器),在处理请求之前[这将需要几毫秒]浏览器尝试连接和Socket.Accept之间的延迟[〜1s]()
我最终尝试做一个虚拟程序来查明问题:
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace SlowHTTPServer
{
class FailServer
{
static void Main()
{
//Create socket object, bind it, listen to 80
Socket listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenerSocket.Bind(new IPEndPoint(IPAddress.Any, 80));
listenerSocket.Listen(64);
while (true)
{
Socket clientConn = listenerSocket.Accept(); //Accept
System.DateTime startTime = System.DateTime.Now;
byte[] buffer = new byte[1024]; //Request header buffer
clientConn.Receive(buffer); //Recieve request header
string reqHeader = Encoding.ASCII.GetString(buffer); //Get the string version of it
//We completely ignore most of the request header lol
//Normally i'd send a response header but...
if (reqHeader.IndexOf("script1") != -1) //script1.js - document.title='hai dere'
clientConn.Send(Encoding.ASCII.GetBytes("document.title='hai dere';"));
else if (reqHeader.IndexOf("script2") != -1) //script2.js - Get a pretty background color onload
clientConn.Send(Encoding.ASCII.GetBytes("window.onload=function(){document.body.style.backgroundColor='#FF99FF';};"));
else if (reqHeader.IndexOf("iframe") != -1) //Noob iframe that just has text.
clientConn.Send(Encoding.ASCII.GetBytes("blargh zargh nargh dargh pikachu tangerine zombie destroy annihilate"));
else //hai dere is the body.innerHTML, load script1.js and script2.js
clientConn.Send(Encoding.ASCII.GetBytes("<html><head><script src='script1.js'></script><script src='script2.js'></script></head><body>mainPage<iframe src='iframe.html'>u no haz iframe</iframe></body></html>"));
clientConn.Close(); //Close the connection to client. We've done such a good job!
System.Console.WriteLine((System.DateTime.Now - startTime).TotalMilliseconds);
}
}
}
}
...而我现在完全糊涂了,因为上面的程序将成为网页脚本+ + iframe中的网页浏览器在2秒的时间跨度[从本地连接到本地主机,Windows防火墙+防病毒关闭]。使用像Apache这样的服务器,[当然在文件系统中使用预先创建的文件]的请求肯定会在不到100毫秒的时间内处理。
从我所看到的,我发布的代码是一个非常简洁的http服务器。如果我发送响应标题,性能不会改变。
问题就变得时,我有30 + JavaScript的脚本文件的项目非常恼人,以20+秒的页面完全加载[当脚本这是不能接受的所有< 10 KB]
如果你看看在脚本中,您会注意到我跟踪的是套接字何时接收以及何时关闭,并且通常处理时间仅为1-10毫秒,这意味着http服务器和Web浏览器之间的延迟[在连接之前被接受?]
我很难过,需要帮助。 谢谢。
其他说明: - 我写的“真实”服务器接受客户端连接并将它们传递给另一个线程来完成这项工作,因此发送字节和关闭连接的任务并不是这么简单的原因落后。 - 绑定到端口80,测试代码运行程序并导航到http://127.0.0.1/或http://localhost/
图片:
Chrome's developer tools showing the load times
附加程序:
我试图通过创建一个模拟问题非常简单的服务器/客户端程序...该问题未被重现,连接时间为1毫秒。我进一步难倒
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace SlowSocketAccept
{
class Program
{
static DateTime connectionBeginTime;
static bool listening = false;
static void Main(string[] args)
{
new Thread(ClientThread).Start();
Socket listenerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenerSocket.Bind(new IPEndPoint(IPAddress.Any, 80));
listenerSocket.Listen(80);
listening = true;
Socket newConn = listenerSocket.Accept();
byte[] reqHeader = new byte[1024];
newConn.Receive(reqHeader);
newConn.Send(Encoding.ASCII.GetBytes("Response Header\r\n\r\nContent"));
newConn.Close();
Console.WriteLine("Elapsed time: {0} ms", (DateTime.Now - connectionBeginTime).TotalMilliseconds);
}
static void ClientThread()
{
while (listening == false) ; //Busy wait, whatever it's an example
System.Threading.Thread.Sleep(10); //Wait for accept to be called =/
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connectionBeginTime = DateTime.Now;
s.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 80));
s.Send(Encoding.ASCII.GetBytes("Request Header"));
byte[] response = new byte[1024];
s.Receive(response);
}
}
}
[a,b为主题]
一)启动线程 'B'
B)忙等到设置一个标志说这没关系连接
一)创建套接字,开始听80,设置一个标志告诉B可以连接
b)创建套接字,存储当前时间,并连接到127.0.0。a)线程接受连接并开始监听
b)线程发送一个虚拟字符串[我们的请求头文件]
a)接受虚拟字符串,然后发送一个虚拟字符串返回[响应头文件+的含量]
a)紧靠连接
经过时间为约1毫秒=/
如果我转到127.0.0.1,该解决方案会将我的加载时间缩短很多[从30秒到1秒]。但是,如果我导航到本地主机,而加载时间仍然是20+秒,这对我来说没有意义,因为根据主机文件localhost == 127.0.0.1。任何想法可能会发生什么?防病毒功能已禁用。如果我转到192.168.0.194 [我的网络上的我的IP],那么加载时间也是1秒,而不是30秒。 – Warty 2010-08-13 22:10:29
总猜在这里,但你看看头?如果添加“Host:localhost”标头会导致标头大小超过1024字节(因为您没有检查标题,只能读取1024字节),这可能会导致问题 - 服务器可能会在之前开始发送浏览器预计会收到任何东西。这在本地主机上尤其明显,因为几乎没有延迟。 – cHao 2010-08-13 22:48:20
顺便说一句,你的代码真的应该看标题,并确保你有一个有效的请求。浏览器通常会做正确的事情,但请参阅上文。而少咸味的人物会找到一些方法来利用松懈的检查。 – cHao 2010-08-13 22:53:55