TcpListener AcceptSocket()为每个单个GET请求接受两个连接

时间:2017-03-26 17:33:09

标签: c# webserver tcplistener

我使用TcpListener启动并运行此Web服务器程序。问题是,对于通过Web浏览器(或Chrome Postman扩展)发出的每个get请求,它会捕获两个请求。

namespace Server
{
    class WebServer2
    {
        private TcpListener listener;
        private int port = 8080;

        public WebServer2()
        {
            try
            {
                listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
                listener.Start();
                Console.WriteLine("Listening...");

                //start the thread which calls the method 'StartListen'
                Thread th = new Thread(new ThreadStart(StartListen));
                th.Start();

            }
            catch (Exception e)
            {
                Console.WriteLine("An Exception Occurred While Listening: " + e.ToString());
            }
        }

        //Recieve Request
        public void StartListen()
        {
            int iStartPos = 0;
            String sRequest;
            String sRequestedFile;
            String sResponse = "";

            while (true)
            {
                //Accept a new connection
                Socket socket = listener.AcceptSocket();

                if (socket.Connected)
                {
                    Console.WriteLine("\nClient Connected");
                    Console.WriteLine("----------------");

                    //Receive data from the client 
                    Byte[] bReceive = new Byte[1024];
                    int i = socket.Receive(bReceive, bReceive.Length, 0);

                    //Convert Byte to String
                    string sBuffer = Encoding.ASCII.GetString(bReceive);

                    //Only GET Request is accepted
                    if (sBuffer.Substring(0, 3) != "GET")
                    {
                        Console.WriteLine("Not a Get Request.");
                        socket.Close();
                        continue;
                    }

                    // Look for HTTP request
                    iStartPos = sBuffer.IndexOf("HTTP", 1);

                    // Get the HTTP text and version e.g. it will return "HTTP/1.1"
                    string sHttpVersion = sBuffer.Substring(iStartPos, 8);

                    // Extract the Requested Type and Requested file/directory
                    sRequest = sBuffer.Substring(0, iStartPos - 1);

                    //If file name not provided
                    if (sRequest.IndexOf(".") < 1)
                    {
                        Console.WriteLine("File name not Provided!");
                        socket.Close();
                        continue;
                    }

                    //Extract the requested file name
                    iStartPos = sRequest.LastIndexOf("/") + 1;
                    sRequestedFile = sRequest.Substring(iStartPos);
                    Console.WriteLine("Requested File: " + sRequestedFile);

                    int iTotBytes = 0;
                    sResponse = "";

                    FileStream fs = new FileStream(sRequestedFile, FileMode.Open, FileAccess.Read, FileShare.Read);
                    BinaryReader reader = new BinaryReader(fs);

                    byte[] bytes = new byte[fs.Length];
                    int read;
                    while ((read = reader.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        // Read from the file and write the data to the network
                        sResponse = sResponse + Encoding.ASCII.GetString(bytes, 0, read);
                        iTotBytes = iTotBytes + read;
                    }
                    reader.Close();
                    fs.Close();

                    SendHeader(sHttpVersion, "text/html", iTotBytes, " 200 OK", ref socket);
                    SendToBrowser(bytes, ref socket);

                    socket.Send(bytes, bytes.Length, 0);
                    socket.Close();
                }
            }
        }

        // Overloaded Function, takes string, convert to bytes and calls 
        // overloaded sendToBrowserFunction.
        public void SendToBrowser(String sData, ref Socket socket)
        {
            SendToBrowser(Encoding.ASCII.GetBytes(sData), ref socket);
        }

        /// Sends data to the browser (client)
        public void SendToBrowser(Byte[] bSendData, ref Socket socket)
        {
            int numBytes = 0;

            try
            {
                if (socket.Connected)
                {
                    if ((numBytes = socket.Send(bSendData, bSendData.Length, 0)) == -1)
                        Console.WriteLine("Socket Error");
                }
                else
                    Console.WriteLine("Connection Dropped!");
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: {0} ", e);
            }
        }

        // This function send the Header Information to the client (Browser)
        public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket socket)
        {

            String sBuffer = "";
            Byte[] bSendData;

            if (sStatusCode.Equals("404") || sStatusCode.Equals("400"))
            {
                sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
                sBuffer = sBuffer + "Server: MyServer\r\n";
                sBuffer = sBuffer + "Content-Length: " + 0 + "\r\n\r\n";

                bSendData = Encoding.ASCII.GetBytes(sBuffer);

                SendToBrowser(bSendData, ref socket);
            }
            else
            {
                sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
                sBuffer = sBuffer + "Server: MyServer\r\n";
                sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
                sBuffer = sBuffer + "Accept-Ranges: bytes\r\n";
                sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";

                bSendData = Encoding.ASCII.GetBytes(sBuffer);

                SendToBrowser(bSendData, ref socket);
            }
        }
    }
}

Single request made by chrome against http://localhost:8080/page1.html

Request made by Postman Extension

有趣的是,当我通过我的客户端程序(使用TcpClient)发送请求时,一切正常。

1 个答案:

答案 0 :(得分:0)

我测试了你的服务器并获得了类似的结果:

  • Chrome会自动为每个请求请求favicon.ico文件。这会为您的服务器生成额外的GET请求。
  • Firefox不会这样做,只需每次刷新生成一个请求。

然后我遇到了第二个问题,这是你邮差截图中的问题。

  • Chrome(包括在其中运行的邮递员扩展程序)重新连接 没有发送任何东西,所以服务器“挂起”,直到你得到一个 响应填充\ 0(空字符)。
  • 这是Chrome预测服务的一部分,可以更快地加载后续请求。您可以在设置(高级)&gt;下禁用此行为。隐私:

Chrome's prediction service option

  • 在您的服务器实现中,如果没有后续的GET请求,则会导致“非获取请求”输出(相反,Chrome发送\ 0表示其不发送任何内容)。

注意:我在实际邮递员application中没有遇到任何此类问题。

当服务器等待chrome发送请求时,它无法为任何其他请求提供服务。为防止这种情况发生,请考虑使用asynchronous approach