【问题标题】:TCPClient returns 400 most of timesTCPClient 大多数时候返回 400
【发布时间】:2018-03-19 18:45:19
【问题描述】:

我正在 C# 中创建一个 TCP 连接到一些使用 HTTP 分析请求的 mp3 流。 当我打开连接时,我总是使用

关闭它
tcpClient.GetStream().Close();
tcpClient.Close();

我也试过用:

client.Client.Disconnect(false);

如果我再次运行我的应用程序并重新连接,我会在响应标头中收到 400(错误请求)和连接关闭,即使我使用“netstat”看到连接不再存在。 这是我到目前为止的代码:

string headers = new string [] {
                    "GET /stream HTTP/1.0", 
                    "Host: sci.streamingmurah.com:8032", 
                    "Connection: keep-alive", 
                    "Accept-Encoding: identity;q=1, *;q=0", 
                    "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", 
                    "Accept: */*",
                    "Referer: 82.XX.XX.XX", 
                    "Accept-Language: en-US,en;q=0.8,he;q=0.6"
            };
try
{
    using (TcpClient client = new TcpClient())
    {
        client.SendTimeout = 5000;
        client.ReceiveTimeout = 5000;
        client.Connect(host, port);
        using (NetworkStream ns = client.GetStream())
        {

            foreach (string requestHeader in headers)
            {
                Debug.WriteLine("Request Header: " + requestHeader);

                byte[] headerBytes = Encoding.ASCII.GetBytes(requestHeader);
                ns.Write(headerBytes, 0, headerBytes.Length);
                ns.WriteByte(13);
                ns.WriteByte(10);
            }

            ns.WriteByte(13);
            ns.WriteByte(10);

            List<string> responseHeaders = new List<string>();

            string responseHeader;
            while (Utils.ReadLine(ns, Encoding.ASCII, out responseHeader) && responseHeader.Length > 0)
            {
                responseHeaders.Add(responseHeader);
            }
            //Response headers contains 
            if (responseHeaders.Count == 0)
            {
                traceInfo.AddLine(TraceInfo.EntryKind.Alert, "Response is empty");
                client.GetStream().Close();
                client.Close();
                //client.Client.Disconnect(false);
                return null;
            }

            Playable pl = HandleResponse(responseHeaders.ToArray(), ns);
            client.GetStream().Close();
            client.Close();
            return pl;
        }
    }
}
catch (Exception e)
{
    traceInfo.AddLine(TraceInfo.EntryKind.Alert, String.Format("Exception: {0}", e.Message));
}

return null;

当然 - 如果我在 Chrome 中运行流,它总是有效的。所以我在做的事情一定是错的。 有什么想法吗?

谢谢

【问题讨论】:

  • 可能是因为缺少Content-Length。 (为什么不直接使用 WebClient 或 HttpClient)
  • @L.B:这是一个 GET 请求。它没有内容,因此没有使用 Content-Length 标头(浏览器也不这样做)。

标签: c# asp.net .net tcp tcpclient


【解决方案1】:

您发送每一行的内容以及每个\r\n 各自在其自己的Write 中。这样,请求可能会分布在多个 TCP 数据包上,这在理论上不是问题——因为 TCP 只是一个没有隐式消息边界的数据流。但是,一些实验表明,在这种情况下,这实际上是一个问题:如果一个人在一次写入中发送请求(这会导致一个数据包),它将起作用,如果它像您的情况一样分布在多个写入中,它将导致在400 Bad Request

我的猜测是,在 Web 服务器前面或服务器内部都有一些保护措施,试图检测像 Slowloris 这样的 DOS 攻击,其中攻击者将 HTTP 请求传播到许多数据包上,中间有很多延迟。尽管您没有进行此类攻击,但您的代码引起的行为(请求分布在多个数据包中)可能会触发此 DOS 检测,然后提前拒绝该请求。

解决方法不是立即将请求标头的每个部分写入套接字,而是将所有内容收集到某个内部缓冲区中,然后将该缓冲区发送到单个写入套接字中。

【讨论】:

  • 这是一个完美的答案!我将所有标题添加到 StringBuilder 中,然后一次编写所有内容。它工作得很好。谢谢!!
猜你喜欢
  • 2021-12-21
  • 2020-12-11
  • 2014-11-04
  • 1970-01-01
  • 2020-03-26
  • 2015-08-12
  • 2017-03-04
  • 1970-01-01
  • 2015-03-15
相关资源
最近更新 更多