C# 尝试连接的浏览器与Socket.Accept()之间的长延迟[~1s]

C# 尝试连接的浏览器与Socket.Accept()之间的长延迟[~1s],c#,javascript,http,sockets,browser,C#,Javascript,Http,Sockets,Browser,问题概述:我已经在编写自定义http服务器应用程序一段时间了。我发现,当任何网络浏览器连接到我的服务器应用程序时,在处理请求之前,都会有0.5-1秒的“延迟”(根据Google Chrome),这需要几毫秒的时间 我最终尝试制作一个虚拟程序来查明问题: using System.Text; using System.Net; using System.Net.Sockets; namespace SlowHTTPServer { class FailServer {

问题概述:我已经在编写自定义http服务器应用程序一段时间了。我发现,当任何网络浏览器连接到我的服务器应用程序时,在处理请求之前,都会有0.5-1秒的“延迟”(根据Google Chrome),这需要几毫秒的时间

我最终尝试制作一个虚拟程序来查明问题:

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);
            }
        }
    }
}
[a和b是线程]
a) 启动线程“b”
b) 忙碌等待,直到A设置了一个标志,表示可以连接
a) 创建套接字,开始收听80,设置一个标志告诉B可以连接
b) 创建套接字,存储当前时间,并连接到127.0.0.1:80[本地主机:80]
a) 线程接受连接并开始侦听
b) 线程发送一个伪字符串[我们的请求头]
a) 接受伪字符串,然后将伪字符串发回[响应头+内容]
a) 密切联系


运行时间约为1毫秒=/

,除非您包含一个内容长度头,并指定您正在使用HTTP 1.0,或者连接应关闭,否则浏览器将一直读取内容,直到它注意到连接已关闭(这可能需要一段时间)

确保您的应用程序正在发送内容长度标题和“连接:关闭”


此外,您应该在关闭客户端套接字之前关闭它。这会告诉.net(也许还有另一方,我忘了)您已经完成了数据发送,应该将数据刷新到网络并重置连接<代码>关闭是代码方面的事情<代码>关机实际上是从客户端的角度关闭连接。

如果我转到127.0.0.1,该解决方案会将我的加载时间减少很多[从30秒减少到1秒]。但是,如果我导航到localhost,加载时间仍然是20多秒,这对我来说没有意义,因为根据hosts文件,localhost==127.0.0.1。你知道会发生什么吗?防病毒功能已禁用。如果我转到192.168.0.194[我的网络上的ip],那么加载时间也是1秒,而不是30秒。这里是总猜测,但是你看过标题了吗?如果添加“Host:localhost”头导致头的大小超过1024字节(因为您没有检查头,只是读取1024字节),这可能会导致问题——服务器可能会在浏览器预期接收任何内容之前开始发送。这在localhost上尤其明显,因为实际上没有延迟。顺便说一句,您的代码应该查看头,并确保您有一个有效的请求。浏览器通常会做正确的事情,但请参见上文。不那么有趣的角色会找到一些方法来利用松散的检查。在
关闭之前,不需要调用
关闭
<代码>关闭
将根据参数关闭发送或接收,或同时关闭发送和接收<代码>关闭
将同时关闭发送和接收。如果这是您需要的行为,请使用
Shutdown
,如果您不打算发送或接收任何进一步的数据,请使用
Close
。@ItzWarty,glad@cHao的建议大大减少了等待时间;尝试pinglocalhost
vs
ping127.0.0.1
;20秒以上的延迟闻起来很像失败的DNS尝试,然后返回到另一种机制来解析主机名。在
/etc/nsswitch.conf
主机:
行中,
文件是否在
dns
之前?
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);
        }
    }
}