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

标签 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 
    {
        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);
            }
        }
    }
}

...我现在完全糊涂了,因为上面的程序将在 2 秒的时间跨度内向 Web 浏览器提供页面+脚本+iframe [从本地主机连接到本地主机,Windows 防火墙+防病毒软件已关闭]。使用像 Apache 这样的服务器,请求 [当然是在文件系统中使用预先创建的文件] 肯定会在不到 100 毫秒的时间内得到处理。

据我所知,我发布的代码是一个极其精简的 http 服务器。无论是否发送响应 header ,性能都不会改变。

当我的项目包含 30 多个 JavaScript 脚本文件时,问题变得非常烦人,需要 20 多秒才能完全加载页面 [当脚本都是 <10 kb 时这是 Not Acceptable ]

如果您查看脚本,您会注意到我跟踪套接字何时接受以及何时关闭,通常处理时间仅为 1-10 毫秒,这意味着延迟存在于 http 服务器和 web 之间浏览器,[在接受连接之前?]

我很困惑,需要帮助。 谢谢。

其他说明: - 我编写的“真实”服务器接受客户端连接并将它们传递给另一个线程来完成工作,因此发送字节和关闭连接的任务并不是造成如此多延迟的原因。 - 绑定(bind)到端口 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是线程]
a) 启动线程'b'
b) 忙等到 A 设置一个标志说可以连接
a) 创建套接字,开始监听 80,设置一个标志告诉 B 可以连接
b) 创建套接字,存储当前时间,并连接到 127.0.0.1:80 [localhost:80]
a) 线程接受连接并开始监听
b) 线程发送一个虚拟字符串[我们的请求头]
a) 接受虚拟字符串,然后发回一个虚拟字符串 [响应头 + 内容]
a) 关闭连接

耗时大约是1毫秒=/

最佳答案

除非您包含一个 Content-Length header ——并指定您使用的是 HTTP 1.0,或者连接应该关闭——浏览器会一直读取内容,直到它注意到连接已关闭(这可能需要而)。

确保您的应用正在发送 Content-Length header 和“连接:关闭”。

此外,您应该在关闭客户端套接字之前将其关闭。这告诉 .net(也许还有其他方面,我忘记了)您已完成发送数据,并且应该将其刷新到网络并重置连接。 Close 是代码方面的事情; Shutdown 从客户端的 Angular 来看实际上是关闭连接。

关于c# - 浏览器尝试连接和 Socket.Accept() 之间的长时间延迟 [~1s],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3476404/

相关文章:

c# - EF Core 与 Postgres 正在生成负主键

javascript - 单击可折叠内容使其折叠

javascript - Protractor :如何获取兄弟元素

apache - 将android连接到数据库

java - 来自 JSONObject 的 StringEntity 对象给出 java.io.UnsupportedEncodingException

C# 无法设置对象

c# - 使用 .NET 的现代 UI 桌面设计

c# - 将控件添加到 FlowLayoutPanel 时意外的索引更改

javascript - 使用 css 透视图检测滚动行为

windows - 实时HTTP流写入控制台