HTTP CONNECT stream.ReadToEnd 需要无限时间

HTTP CONNECT stream.ReadToEnd takes infinite time

我正在尝试构建一个应该能够使用 HTTP CONNECT 代理隧道的 class。 我当前的代码挂在 DoHttpConnect() - "var retvar = await sr.ReadToEndAsync();" 并且从未到达 Console.WriteLine(retvar);

连接class:

 public class HttpConnect : BaseProxyModule
{
    public HttpConnect(HostPortCollection proxyInformation) : base(proxyInformation)
    {
    }

    public override async Task<Stream> OpenStreamAsync(HostPortCollection dstSrv)
    {
        var socket = new TcpClient();
        if (await SwallowExceptionUtils.TryExec(() => socket.ConnectAsync(_proxyInformation.Addr, _proxyInformation.Port)) && socket.Connected)
        {
            var nStream = socket.GetStream();
            var cmd = ProxyCommandBuildUtils.GenerateHttpConnectCommand(dstSrv.Host, dstSrv.Port);

            await nStream.WriteAsync(cmd, 0, cmd.Length);
            var sr = new StreamReader(nStream);
            var cLine = await sr.ReadLineAsync();
            var fLineElem = cLine.Split(' ');

            if (fLineElem.Length >= 1 && fLineElem[1] == "200")
            {
                await sr.ReadLineAsync();
                return nStream;
            }
        }
        return null;
    }

    internal class ProxyCommandBuildUtils
    {
        private const string HTTP_PROXY_CONNECT_CMD = "CONNECT {0}:{1} HTTP/1.1\r\nHost: {0}\r\n\r\n";

        public static byte[] GenerateHttpConnectCommand(string host, int port)
        {
            string connectCmd = String.Format(CultureInfo.InvariantCulture, HTTP_PROXY_CONNECT_CMD, host, port.ToString(CultureInfo.InvariantCulture));
            return connectCmd.GetBytes();
        }
    }

用法:

      public static void Main(string[] args)
    {
        DoHttpConnect().Wait();
        Debugger.Break();
    }

    public static async Task DoHttpConnect()
    {
        //var hCon = new HttpConnect(new HostPortCollection("5.135.195.166", 3128)); //Doesn't work..
        var hCon = new HttpConnect(new HostPortCollection("109.75.213.146", 53281)); //Doesn't work either :/
        var pStream = await hCon.OpenStreamAsync(new HostPortCollection("www.myip.ch", 80));
        var request = FormatHttpRequest(new Uri("http://www.myip.ch/"));
        using (var sw = new StreamWriter(pStream))
        using (var sr = new StreamReader(pStream))
        {
            await sw.WriteLineAsync(request);

            var retvar = await sr.ReadToEndAsync(); //Takes till the end of time itself
            Console.WriteLine(retvar);
        }
        Debugger.Break();
    }
    private static string FormatHttpRequest(Uri url)
    {
        return $"GET {url.LocalPath}  HTTP/1.0\r\nHost: {url.DnsSafeHost}\r\n\r\n";
    }

WriteLineAsync() 调用实际上并没有立即写入网络。相反,StreamWriter 将其保存在缓冲区中。因此,服务器从未真正收到您的请求,因此不会向您发送回复。

您应该通过执行以下操作之一强制缓冲区写出到网络:

  1. StreamWriter 开启 AutoFlush (reference),这将使它在每次调用 WriteLineAsync()
  2. 时刷新缓冲区
  3. 显式调用 FlushAsync() (reference)
  4. 通过重写如下代码关闭流(这将刷新缓冲区):

    using (var sr = new StreamReader(pStream))
    {
        using (var sw = new StreamWriter(pStream))
        {
            await sw.WriteLineAsync(request);
        }
    
        var retvar = await sr.ReadToEndAsync();
        Console.WriteLine(retvar);
    }