• Socket 实现HttpClient


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics.Contracts;
    using System.Collections.Specialized;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Net.Security;
    using System.Net.Mime;
    using System.Reflection;
    
    namespace Rocky.Net
    {
        internal class HttpClient
        {
            #region Fields
            private ProxyEntity _proxy;
            private HttpRequestEntity _entity;
            private Socket _sock;
            private object[] _args;
            #endregion
    
            #region Properties
            public ProxyEntity Proxy
            {
                get { return _proxy; }
            }
            public WebHeaderCollection Headers
            {
                get { return _entity.Headers; }
            }
            public NameValueCollection Form
            {
                get { return _entity.Form; }
            }
            public bool KeepAlive { get; set; }
            public bool HeadMethod { get; set; }
            public int SendReceiveTimeout { get; set; }
            #endregion
    
            #region Constructors
            public HttpClientSlim(IPEndPoint tunnel)
            {
                Contract.Requires(tunnel != null);
    
                _proxy = new ProxyEntity()
                {
                    ProxyType = ProxyType.ptHTTP,
                    Address = tunnel
                };
                _entity = new HttpRequestEntity();
                _entity.Headers[HttpRequestHeader.Accept] = "*/*";
                _entity.Headers[HttpRequestHeader.Referer] = HttpClient.DefaultReferer;
                _entity.Headers[HttpRequestHeader.UserAgent] = HttpClient.DefaultUserAgent;
                _args = new object[3];
                this.KeepAlive = true;
                this.SendReceiveTimeout = 1000 * 30;
            }
            #endregion
    
            #region Methods
            public HttpResponseEntity GetResponse(Uri requestUri)
            {
                Contract.Requires(requestUri != null);
    
                _entity.Headers[HttpRequestHeader.Host] = requestUri.Host;
                _entity.Headers["Proxy-Connection"] = _entity.Headers[HttpRequestHeader.Connection] = this.KeepAlive ? "keep-alive" : "close";
                string sForm = null;
                if (_entity.HasValue)
                {
                    sForm = _entity.GetFormString();
                    _entity.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
                    _entity.Headers[HttpRequestHeader.ContentLength] = Encoding.UTF8.GetByteCount(sForm).ToString();
                }
    
                _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _sock.ReceiveTimeout = _sock.SendTimeout = this.SendReceiveTimeout;
                try
                {
                    _sock.Connect(_proxy.Address);
                    var ipe = SocketHelper.ParseHost(string.Format("{0}:{1}", requestUri.Host, requestUri.Port));
                    var proxyData = ProxyUtility.GetRequestData(_proxy, ipe);
                    int sent = _sock.Send(proxyData);
                    Array.Resize(ref proxyData, 256);
                    int recv = _sock.Receive(proxyData);
                    ProxyUtility.ValidateResponseStatus(_proxy, proxyData);
    
                    var netStream = new NetworkStream(_sock, FileAccess.ReadWrite, false);
    
                    Stream src = netStream;
                    var writer = new StreamWriter(src, Encoding.ASCII);
                    string method = this.HeadMethod ? WebRequestMethods.Http.Head :
                        sForm == null ? WebRequestMethods.Http.Get : WebRequestMethods.Http.Post;
                    writer.WriteLine("{0} {1} HTTP/1.1", method, requestUri.PathAndQuery);
                    var sHeaders = new StringBuilder(_entity.GetHeadersString());
                    SocketHelper.Logger.DebugFormat("RequestHeaders:\r\n{0}\r\n", sHeaders);
                    writer.WriteLine(sHeaders);
                    writer.WriteLine();
                    writer.Flush();
                    if (sForm != null)
                    {
                        if (requestUri.Scheme == Uri.UriSchemeHttps)
                        {
                            var sslStream = new SslStream(src);
                            sslStream.AuthenticateAsClient(requestUri.Host);
                            src = sslStream;
                        }
                        writer = new StreamWriter(src, Encoding.UTF8);
                        writer.Write(sForm);
                        writer.Flush();
                    }
    
                    var response = new HttpResponseEntity();
                    var reader = new StreamReader(src, Encoding.ASCII);
    
                    //HTTP/1.1 200 OK
                    string line = reader.ReadLine();
                    var status = line.Split(new char[] { ' ' }, 3);
                    if (status.Length != 3)
                    {
                        throw new InvalidOperationException("InternalServerError");
                    }
                    response.StatusCode = (HttpStatusCode)int.Parse(status[1]);
                    response.StatusDescription = status[2];
                    sHeaders.Length = 0;
                    while (!string.IsNullOrEmpty(line = reader.ReadLine()))
                    {
                        int i = line.IndexOf(":");
                        string name = line.Substring(0, i), value = line.Substring(i + 2);
                        response.Headers.Add(name, value);
                        sHeaders.AppendLine(line);
                    }
                    SocketHelper.Logger.DebugFormat("ResponseHeaders:\r\n{0}\r\n", sHeaders);
                    string contentType = response.Headers[HttpResponseHeader.ContentType];
                    int charsetIndex;
                    if (string.IsNullOrEmpty(contentType) || (charsetIndex = contentType.LastIndexOf("=")) == -1)
                    {
                        response.ContentEncoding = Encoding.UTF8;
                    }
                    else
                    {
                        string charset = contentType.Substring(charsetIndex + 1);
                        response.ContentEncoding = Encoding.GetEncoding(charset);
                    }
    
                    if (!this.HeadMethod)
                    {
                        string bufferedString;
                        this.SetEncoding(reader, response.ContentEncoding, out bufferedString);
                        response.ResponseText = bufferedString;
                        response.ResponseText += reader.ReadToEnd();
                    }
    
                    return response;
                }
                finally
                {
                    if (_sock.Connected)
                    {
                        _sock.Disconnect(this.KeepAlive);
                    }
                }
            }
    
            private void SetEncoding(StreamReader reader, Encoding encoding, out string bufferedString)
            {
                Type type = reader.GetType();
                var flags = BindingFlags.NonPublic | BindingFlags.Instance;
                var field = type.GetField("charPos", flags);
                int charPos = Convert.ToInt32(field.GetValue(reader));
                field = type.GetField("charLen", flags);
                int charLen = Convert.ToInt32(field.GetValue(reader));
                field = type.GetField("byteBuffer", flags);
                byte[] byteBuffer = (byte[])field.GetValue(reader);
                bufferedString = encoding.GetString(byteBuffer, charPos, charLen - charPos);
    
                field = type.GetField("encoding", flags);
                field.SetValue(reader, encoding);
    
                field = type.GetField("decoder", flags);
                field.SetValue(reader, encoding.GetDecoder());
    
                reader.DiscardBufferedData();
            }
            #endregion
        }
    }
  • 相关阅读:
    SqlServer查询优化方法
    关于导入excel问题
    修改SQL数据库中表字段类型时,报“一个或多个对象访问此列”错误的解决方法
    软件架构之我见
    算法-插入排序
    算法-快速排序
    WCF系列 Restful WCF
    WCF系列 基础概念
    cocos2dx-是男人就坚持20s 练手项目
    nodejs 聊天室简单实现
  • 原文地址:https://www.cnblogs.com/Googler/p/2966627.html
Copyright © 2020-2023  润新知