有人说用 Socket 请求 http 服务效率要比 HttpWebRequest 高很多, 但是又没有提供源码或者对比测试结果. 我对此很好奇, 到底能差多少? 所以决定自己写个类实现 Socket 请求 http 的功能.
下面的代码实现了基本的 http ,https 请求, 支持 gzip 解压, 分块传输.
经本人多次试验, 得出如下结论:
如果仅用 Socket 获取文本类型的内容, 且不考虑分块传输的情况, 那么 Socket 方式可比 HttpWebRequest 方式效率高 30%-40%.
如果考虑更多因素,需要做更多处理, 所以多数时候效率不如 HttpWebRequest, 当然与我写的代码效率有很大关系.
本文首发地址 http://blog.itnmg.net/socket-http/
欢迎共同探讨技术问题,提供建议, 请留言,我会尽快回复.


1 /* Name: Socket 实现 http 协议全功能版 2 * Version: v0.6 3 * Description: 此版本实现了 http 及 https 的 get 或 post 访问, 自动处理301,302跳转, 支持 gzip 解压, 分块传输. 4 * 支持的操作: 获取文本,图片,文件形式的内容. 5 * 使用方法: new HttpWebSocket(); 调用实例的 Get.... 方法. 6 * 声明: 本代码仅做技术探讨,可任意转载,请勿用于商业用途. 7 * 本人博客: http://blog.itnmg.net http://www.cnblogs.com/lhg-net 8 * 创建日期: 2013-01-15 9 * 修订日期: 2013-06-03 10 */ 11 using System; 12 using System.Collections.Generic; 13 using System.Net; 14 using System.Net.Sockets; 15 using System.Net.Security; 16 using System.Text; 17 using System.Text.RegularExpressions; 18 using System.IO; 19 using System.IO.Compression; 20 using System.Web; 21 using System.Drawing; 22 using System.Security.Cryptography.X509Certificates; 23 24 namespace ExtLibrary.Net 25 { 26 class HttpWebSocket 27 { 28 /// <summary> 29 /// 获取或设置请求与回应的超时时间,默认3秒. 30 /// </summary> 31 public int TimeOut 32 { 33 get; 34 set; 35 } 36 37 /// <summary> 38 /// 获取或设置请求cookie 39 /// </summary> 40 public List<string> Cookies 41 { 42 get; 43 set; 44 } 45 46 /// <summary> 47 /// 获取请求返回的 HTTP 头部内容 48 /// </summary> 49 public HttpHeader HttpHeaders 50 { 51 get; 52 internal set; 53 } 54 55 /// <summary> 56 /// 获取或设置错误信息分隔符 57 /// </summary> 58 private string ErrorMessageSeparate; 59 60 61 62 public HttpWebSocket() 63 { 64 this.TimeOut = 3; 65 this.Cookies = new List<string>(); 66 this.ErrorMessageSeparate = ";;"; 67 this.HttpHeaders = new HttpHeader(); 68 } 69 70 71 72 /// <summary> 73 /// get或post方式请求一个 http 或 https 地址.使用 Socket 方式 74 /// </summary> 75 /// <param name="url">请求绝对地址</param> 76 /// <param name="referer">请求来源地址,可为空</param> 77 /// <param name="postData">post请求参数. 设置空值为get方式请求</param> 78 /// <returns>返回图像</returns> 79 public Image GetImageUseSocket( string url, string referer, string postData = null ) 80 { 81 Image result = null; 82 MemoryStream ms = this.GetSocketResult( url, referer, postData ); 83 84 try 85 { 86 if ( ms != null ) 87 { 88 result = Image.FromStream( ms ); 89 } 90 } 91 catch ( Exception e ) 92 { 93 string ss = e.Message; 94 } 95 96 return result; 97 } 98 99 /// <summary> 100 /// get或post方式请求一个 http 或 https 地址.使用 Socket 方式 101 /// </summary> 102 /// <param name="url">请求绝对地址</param> 103 /// <param name="postData">post请求参数. 设置空值为get方式请求</param> 104 /// <returns>返回 html 内容,如果发生异常将返回上次http状态码及异常信息</returns> 105 public string GetHtmlUseSocket( string url, string postData = null ) 106 { 107 return this.GetHtmlUseSocket( url, null, postData ); 108 } 109 110 /// <summary> 111 /// get或post方式请求一个 http 或 https 地址.使用 Socket 方式 112 /// </summary> 113 /// <param name="url">请求绝对地址</param> 114 /// <param name="referer">请求来源地址,可为空</param> 115 /// <param name="postData">post请求参数. 设置空值为get方式请求</param> 116 /// <returns>返回 html 内容,如果发生异常将返回上次http状态码及异常信息</returns> 117 public string GetHtmlUseSocket( string url, string referer, string postData = null ) 118 { 119 string result = string.Empty; 120 121 try 122 { 123 MemoryStream ms = this.GetSocketResult( url, referer, postData ); 124 125 if ( ms != null ) 126 { 127 result = Encoding.GetEncoding( string.IsNullOrWhiteSpace( this.HttpHeaders.Charset ) ? "UTF-8" : this.HttpHeaders.Charset ).GetString( ms.ToArray() ); 128 } 129 } 130 catch ( SocketException se ) 131 { 132 result = this.HttpHeaders.ResponseStatusCode + this.ErrorMessageSeparate + se.ErrorCode.ToString() + this.ErrorMessageSeparate + se.SocketErrorCode.ToString( "G" ) + this.ErrorMessageSeparate + se.Message; 133 } 134 catch ( Exception e ) 135 { 136 result = this.HttpHeaders.ResponseStatusCode + this.ErrorMessageSeparate + e.Message; 137 } 138 139 return result; 140 } 141 142 /// <summary> 143 /// get或post方式请求一个 http 或 https 地址. 144 /// </summary> 145 /// <param name="url">请求绝对地址</param> 146 /// <param name="referer">请求来源地址,可为空</param> 147 /// <param name="postData">post请求参数. 设置空值为get方式请求</param> 148 /// <returns>返回的已解压的数据内容</returns> 149 private MemoryStream GetSocketResult( string url, string referer, string postData ) 150 { 151 if ( string.IsNullOrWhiteSpace( url ) ) 152 {