【问题标题】:C# Mini Http Server, Knowing when to close a connectionC# Mini Http Server,知道何时关闭连接
【发布时间】:2013-07-31 13:41:16
【问题描述】:

我一直在使用 TcpListener 类在 C# 中编写我自己的 http Web 服务器。现在在任何人提到这一点之前,我知道 HttpListener,但是在之前使用它之后,由于防火墙异常和需要拥有管理员帐户等,我遇到了一些问题。对于我的应用程序,它只是更容易制作简单的内置网络服务器。我一直在使用 python 应用程序连接到我的 C# 网络服务器,并发送一个简单的 GET 请求,然后接收一个简单的响应。

我的问题是......服务器应该关闭连接还是客户端?我问是因为如果我在发送响应后关闭服务器中的连接,我的 Python 应用程序并不总是能够读取所有响应。相反,会抛出一个套接字错误“错误 10054,'Connection reset by peer'”。但是,如果我强制 python 应用程序关闭连接,我不确定如何在我的 C# 服务器上检测到它,因为 C# TcpClient 不包含断开连接事件。那我该怎么办?我如何知道已连接的客户端何时收到完整响应以便我可以关闭连接?

目前,这有效(使用线程睡眠)

// Write headers and body to the Socket
        NetworkStream Stream = Client.GetStream();

        // Write Headers
        byte[] Buffer = Encoding.UTF8.GetBytes(Headers);
        Stream.Write(Buffer, 0, Buffer.Length);

        // Write Response Data if Request method is not HEAD
        if (Request.RequestMethod != HttpRequestMethod.HEAD)
            Stream.Write(BodyByteArr, 0, BodyByteArr.Length);

        Stream.Flush();

        System.Threading.Thread.Sleep(100);
        Stream.Close();
        Client.Close();

我认为我需要一个比 Thread.Sleep() 更好的替代方案,如果客户端花费的时间超过睡眠时间来接收响应(慢速连接),这可能也不起作用

标头发送到 Http 服务器:

GET /test HTTP/1.1
Host: 127.0.0.1
Connection: close

发回客户端的标头:

HTTP/1.1 200 OK
Date: {Now}
Server: MiniHttp-ASPServer
Content-Type: text/plain; charset=utf-8
Content-Length: {length}
Connection: close

{contents}

【问题讨论】:

  • 你向客户端发送什么标头?
  • 我猜这是一个内容长度问题。我相信内容长度只是正文的长度。您可以稍微调试一下的一种方法是使用强大的客户端(如 chrome)来查看它是否使用 F12 工具处理格式不正确的请求(或者它是否完成了对请求的处理)。
  • 使用网络浏览器,完全没有问题。只有 python 套接字在它可以读取之前存在套接字关闭的问题。这就是整个“Thread.Sleep”发挥作用的地方。如果我删除那个睡眠,python 会得到套接字错误,否则它会工作......所以我想我关闭连接太快了?

标签: c# webserver tcplistener


【解决方案1】:

您是否看过 h[ttp://msdn.microsoft.com/en-us/library/w89fhyex.aspx][1] 上的同步和异步套接字示例

[1]:http://msdn.microsoft.com/en-us/library/w89fhyex.aspx?

我认为您可以将一些逻辑应用到您的解决方案中。在同步服务器示例中(sn-p):

       while (true) {
            Console.WriteLine("Waiting for a connection...");
            // Program is suspended while waiting for an incoming                      connection.
            Socket handler = listener.Accept();
            data = null;

            // An incoming connection needs to be processed.
            while (true) {
                bytes = new byte[1024];
                int bytesRec = handler.Receive(bytes);
                data += Encoding.ASCII.GetString(bytes,0,bytesRec);
                if (data.IndexOf("<EOF>") > -1) {
                    break;
                }
            }

            // Show the data on the console.
            Console.WriteLine( "Text received : {0}", data);

            // Echo the data back to the client.
            byte[] msg = Encoding.ASCII.GetBytes(data);

            handler.Send(msg);
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }

在客户端:

         sender.Connect(remoteEP);

            Console.WriteLine("Socket connected to {0}",
                              sender.RemoteEndPoint.ToString());

            // Encode the data string into a byte array.
            byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");

            // Send the data through the socket.
            int bytesSent = sender.Send(msg);

            // Receive the response from the remote device.
            int bytesRec = sender.Receive(bytes);
            Console.WriteLine("Echoed test = {0}",
                                Encoding.ASCII.GetString(bytes,0,bytesRec));

            // Release the socket.
            sender.Shutdown(SocketShutdown.Both);
            sender.Close();

【讨论】:

  • 好吧,这并不能真正回答我的问题,或者对我有很大帮助。我确实在我的脚本中加入了 Socket.Shutdown()(我完全不知道这个方法),这似乎有点帮助,但我仍然收到了 48 个异步请求中的 2 个套接字错误。越来越近,但不完全:)
  • 好的。好吧,您可能想查看位于 [link] msdn.microsoft.com/en-us/library/… 的 Socket.ReceiveTimeout 属性。此外,我仍然鼓励您运行我给您的上一个链接中的示例,看看它是否会提供一些见解。跨度>
【解决方案2】:

取自 HTTP1.1 RFC:

如果客户端或服务器在 Connection 标头中发送关闭令牌,则该请求将成为连接的最后一个。

因此,当您的服务器关闭连接时,它之前必须使用 Connection: close 标头来回答。

我不知道 C#,它是 TCP 客户端,但有几个原因可能导致套接字上的发送失败。在关闭应用程序之前,我看不到您处理任何这些。

您必须重试发送答案,直到您确定它已被完整阅读。 我认为您的 Connection: close 标头永远不会到达您的客户端,这就是使用“对等方重置连接”的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多