软件编程
位置:首页>> 软件编程>> C#编程>> c#使用Socket发送HTTP/HTTPS请求的实现代码

c#使用Socket发送HTTP/HTTPS请求的实现代码

作者:mdxy-dxy  发布时间:2023-10-12 07:10:00 

标签:c#,Socket,HTTP/HTTPS请求

C# 自带的HttpWebRequest效率太低,对于自组HTTP封包不好操作。

在写超级SQL注入工具时,研究了很长一段时间如何使用Socket来发送HTTP、HTTPS请求。

经过一年的修改和测试,可完美、高效发送并解析HTTP/HTTPS请求。修改过无数次bug。

在这里把核心代码分享出来,供大家学习或做开发参考。

用这个代码写了一个简单的HTTP发包工具。供大家参考。

c#使用Socket发送HTTP/HTTPS请求的实现代码

工具下载:

HTTPTool.rar

核心类:HTTP.cs


using System;
using System.Collections.Generic;
using System.Text;
using tools;
using System.Net;
using System.Net.Sockets;
using System.IO.Compression;
using System.IO;
using System.Net.Security;
using System.Text.RegularExpressions;
using System.Threading;
using System.Diagnostics;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using HTTPTool;

namespace tools
{
 public class HTTP
 {
   public const char T = '
';
   public const String CT = "
";
   public const String CTRL = "

";
   public const String Content_Length_Str = "content-length: ";
   public const String Content_Length_Str_M = "Content-Length: ";
   public const String Content_Length = "content-length";
   public const String Content_Encoding = "content-encoding";
   public const String Transfer_Encoding = "transfer-encoding";
   public const String Connection = "connection";
   public static Main main = null;
   public static long index = 0;
   public void initMain(Main m)
   {
     main = m;
   }

/**
    *
    发生异常尝试重连
    *
    */
   public static ServerInfo sendRequestRetry(Boolean isSSL, int tryCount, String host, int port, String payload, String request, int timeout, String encoding, Boolean foward_302)
   {
     int count = 0;
     Interlocked.Increment(ref index);
     ServerInfo server = new ServerInfo();
     timeout = timeout * 1000;
     while (true)
     {
       if (count >= tryCount) break;

try
       {
         if (!isSSL)
         {
           server = sendHTTPRequest(count, host, port, payload, request, timeout, encoding, foward_302);
           return server;
         }
         else
         {

server = sendHTTPSRequest(count, host, port, payload, request, timeout, encoding, foward_302);
           return server;

}
       }
       catch (Exception e)
       {
         Tools.SysLog("发包发生异常,正在重试----" + e.Message);
         server.timeout = true;
         continue;
       }
       finally
       {
         count++;
       }

}
     return server;

}

private static void checkContentLength(ref ServerInfo server, ref String request)
   {

//重新计算并设置Content-length
     int sindex = request.IndexOf(CTRL);
     server.reuqestHeader = request;
     if (sindex != -1)
     {
       server.reuqestHeader = request.Substring(0, sindex);
       server.reuqestBody = request.Substring(sindex + 4, request.Length - sindex - 4);
       int contentLength = Encoding.UTF8.GetBytes(server.reuqestBody).Length;
       String newContentLength = Content_Length_Str_M + contentLength;

if (request.IndexOf(Content_Length_Str_M) != -1)
       {
         request = Regex.Replace(request, Content_Length_Str_M + "d+", newContentLength);
       }
       else
       {
         request = request.Insert(sindex, "
" + newContentLength);
       }
     }
     else
     {
       request = Regex.Replace(request, Content_Length_Str + "d+", Content_Length_Str_M + "0");
       request += CTRL;
     }

}

private static void doHeader(ref ServerInfo server, ref String[] headers)
   {

for (int i = 0; i < headers.Length; i++)
     {
       if (i == 0)
       {

server.code = Tools.convertToInt(headers[i].Split(' ')[1]);

}
       else
       {
         String[] kv = Regex.Split(headers[i], ": ");
         String key = kv[0].ToLower();
         if (!server.headers.ContainsKey(key))
         {
           //自动识别编码
           if ("content-type".Equals(key))
           {
             String hecnode = getHTMLEncoding(kv[1], "");
             if (!String.IsNullOrEmpty(hecnode))
             {
               server.encoding = hecnode;
             }
           }
           if (kv.Length > 1)
           {
             server.headers.Add(key, kv[1]);
           }
           else
           {
             server.headers.Add(key, "");
           }
         }
       }
     }

}

private static ServerInfo sendHTTPRequest(int count, String host, int port, String payload, String request, int timeout, String encoding, Boolean foward_302)
   {

String index = Thread.CurrentThread.Name + HTTP.index;
     Stopwatch sw = new Stopwatch();
     sw.Start();
     ServerInfo server = new ServerInfo();
     TcpClient clientSocket = null;
     int sum = 0;
     try
     {
       if (port > 0 && port <= 65556)
       {
         //编码处理
         server.request = request;
         TimeOutSocket tos = new TimeOutSocket();
         clientSocket = tos.Connect(host, port, timeout);
         if (sw.ElapsedMilliseconds >= timeout)
         {
           return server;
         }
         clientSocket.SendTimeout = timeout - tos.useTime;
         if (clientSocket.Connected)
         {
           checkContentLength(ref server, ref request);
           server.request = request;

byte[] requestByte = Encoding.UTF8.GetBytes(request);
           clientSocket.Client.Send(requestByte);
           byte[] responseBody = new byte[1024 * 1000];
           int len = 0;
           //获取header头
           String tmp = "";
           StringBuilder sb = new StringBuilder();
           clientSocket.ReceiveTimeout = timeout - (int)sw.ElapsedMilliseconds;
           do
           {
             byte[] responseHeader = new byte[1];
             len = clientSocket.Client.Receive(responseHeader, 1, SocketFlags.None);
             if (len == 1)
             {

char c = (char)responseHeader[0];
               sb.Append(c);
               if (c.Equals(T))
               {
                 tmp = String.Concat(sb[sb.Length - 4], sb[sb.Length - 3], sb[sb.Length - 2], c);
               }
             }
           } while (!tmp.Equals(CTRL) && sw.ElapsedMilliseconds < timeout);

server.header = sb.ToString().Replace(CTRL, "");
           String[] headers = Regex.Split(server.header, CT);
           if (headers != null && headers.Length > 0)
           {
             //处理header
             doHeader(ref server, ref headers);
             //自动修正编码
             if (!String.IsNullOrEmpty(server.encoding))
             {
               encoding = server.encoding;
             }
             Encoding encod = Encoding.GetEncoding(encoding);

//302 301跳转
             if ((server.code == 302 || server.code == 301) && foward_302)
             {
               StringBuilder rsb = new StringBuilder(server.request);
               int urlStart = server.request.IndexOf(" ") + 1;
               int urlEnd = server.request.IndexOf(" HTTP");
               if (urlStart != -1 && urlEnd != -1)
               {
                 String url = server.request.Substring(urlStart, urlEnd - urlStart);
                 rsb.Remove(urlStart, url.Length);
                 String location = server.headers["location"];
                 if (!server.headers["location"].StartsWith("/") && !server.headers["location"].StartsWith("http"))
                 {
                   location = Tools.getCurrentPath(url) + location;
                 }
                 rsb.Insert(urlStart, location);

return sendHTTPRequest(count, host, port, payload, rsb.ToString(), timeout, encoding, false);
               }

}

//根据请求头解析
             if (server.headers.ContainsKey(Content_Length))
             {
               int length = int.Parse(server.headers[Content_Length]);

while (sum < length && sw.ElapsedMilliseconds < timeout)
               {
                 int readsize = length - sum;
                 len = clientSocket.Client.Receive(responseBody, sum, readsize, SocketFlags.None);
                 if (len > 0)
                 {
                   sum += len;
                 }
               }
             }
             //解析chunked传输
             else if (server.headers.ContainsKey(Transfer_Encoding))
             {
               //读取长度
               int chunkedSize = 0;
               byte[] chunkedByte = new byte[1];
               //读取总长度
               sum = 0;
               do
               {
                 String ctmp = "";
                 do
                 {
                   len = clientSocket.Client.Receive(chunkedByte, 1, SocketFlags.None);
                   ctmp += Encoding.UTF8.GetString(chunkedByte);

} while ((ctmp.IndexOf(CT) == -1) && (sw.ElapsedMilliseconds < timeout));

chunkedSize = Tools.convertToIntBy16(ctmp.Replace(CT, ""));

//chunked的结束0

是结束标志,单个chunked块
结束
                 if (ctmp.Equals(CT))
                 {
                   continue;
                 }
                 if (chunkedSize == 0)
                 {
                   //结束了
                   break;
                 }
                 int onechunkLen = 0;
                 while (onechunkLen < chunkedSize && sw.ElapsedMilliseconds < timeout)
                 {
                   len = clientSocket.Client.Receive(responseBody, sum, chunkedSize - onechunkLen, SocketFlags.None);
                   if (len > 0)
                   {
                     onechunkLen += len;
                     sum += len;
                   }
                 }

//判断
               } while (sw.ElapsedMilliseconds < timeout);
             }
             //connection close方式或未知body长度
             else
             {
               while (sw.ElapsedMilliseconds < timeout)
               {
                 if (clientSocket.Client.Poll(timeout, SelectMode.SelectRead))
                 {
                   if (clientSocket.Available > 0)
                   {
                     len = clientSocket.Client.Receive(responseBody, sum, (1024 * 200) - sum, SocketFlags.None);
                     if (len > 0)
                     {
                       sum += len;
                     }
                   }
                   else
                   {
                     break;
                   }
                 }
               }
             }
             //判断是否gzip
             if (server.headers.ContainsKey(Content_Encoding))
             {
               server.body = unGzip(responseBody, sum, encod);
             }
             else
             {
               server.body = encod.GetString(responseBody, 0, sum);
             }

}
         }

}
     }
     catch (Exception e)
     {
       Exception ee = new Exception("HTTP发包错误!错误消息:" + e.Message + e.TargetSite.Name + "----发包编号:" + index);
       throw ee;
     }
     finally
     {
       sw.Stop();
       server.length = sum;
       server.runTime = (int)sw.ElapsedMilliseconds;
       if (clientSocket != null)
       {
         clientSocket.Close();
       }
     }
     return server;

}

private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
   {
     return true;
   }
   private static ServerInfo sendHTTPSRequest(int count, String host, int port, String payload, String request, int timeout, String encoding, Boolean foward_302)
   {
     String index = Thread.CurrentThread.Name + HTTP.index;
     Stopwatch sw = new Stopwatch();
     sw.Start();
     ServerInfo server = new ServerInfo();

int sum = 0;

TcpClient clientSocket = null; ;

try
     {

if (port > 0 && port <= 65556)
       {

TimeOutSocket tos = new TimeOutSocket();
         clientSocket = tos.Connect(host, port, timeout);
         if (sw.ElapsedMilliseconds >= timeout)
         {
           return server;
         }
         clientSocket.SendTimeout = timeout - tos.useTime;

SslStream ssl = null;
         if (clientSocket.Connected)
         {
           ssl = new SslStream(clientSocket.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate));
           SslProtocols protocol = SslProtocols.Ssl3 | SslProtocols.Ssl2 | SslProtocols.Tls;
           ssl.AuthenticateAsClient(host, null, protocol, false);
           if (ssl.IsAuthenticated)
           {
             checkContentLength(ref server, ref request);
             server.request = request;
             byte[] requestByte = Encoding.UTF8.GetBytes(request);
             ssl.Write(requestByte);
             ssl.Flush();
           }
         }
         server.request = request;
         byte[] responseBody = new byte[1024 * 1000];
         int len = 0;
         //获取header头
         String tmp = "";

StringBuilder sb = new StringBuilder();
         StringBuilder bulider = new StringBuilder();
         clientSocket.ReceiveTimeout = timeout - (int)sw.ElapsedMilliseconds;
         do
         {
           byte[] responseHeader = new byte[1];
           int read = ssl.ReadByte();

char c = (char)read;
           sb.Append(c);
           if (c.Equals(T))
           {
             tmp = String.Concat(sb[sb.Length - 4], sb[sb.Length - 3], sb[sb.Length - 2], c);
           }

} while (!tmp.Equals(CTRL) && sw.ElapsedMilliseconds < timeout);

server.header = sb.ToString().Replace(CTRL, "");
         String[] headers = Regex.Split(server.header, CT);
         //处理header
         doHeader(ref server, ref headers);
         //自动修正编码
         if (!String.IsNullOrEmpty(server.encoding))
         {
           encoding = server.encoding;
         }
         Encoding encod = Encoding.GetEncoding(encoding);
         //302 301跳转
         if ((server.code == 302 || server.code == 301) && foward_302)
         {

int urlStart = server.request.IndexOf(" ");
           int urlEnd = server.request.IndexOf(" HTTP");
           if (urlStart != -1 && urlEnd != -1)
           {
             String url = server.request.Substring(urlStart + 1, urlEnd - urlStart - 1);
             if (!server.headers["location"].StartsWith("/") && !server.headers["location"].StartsWith("https"))
             {
               server.request = server.request.Replace(url, Tools.getCurrentPath(url) + server.headers["location"]);
             }
             else
             {
               server.request = server.request.Replace(url, server.headers["location"]);
             }

return sendHTTPSRequest(count, host, port, payload, server.request, timeout, encoding, false);
           }

}

//根据请求头解析
         if (server.headers.ContainsKey(Content_Length))
         {
           int length = int.Parse(server.headers[Content_Length]);
           while (sum < length && sw.ElapsedMilliseconds < timeout)
           {
             len = ssl.Read(responseBody, sum, length - sum);
             if (len > 0)
             {
               sum += len;
             }
           }
         }
         //解析chunked传输
         else if (server.headers.ContainsKey(Transfer_Encoding))
         {
           //读取长度
           int chunkedSize = 0;
           byte[] chunkedByte = new byte[1];
           //读取总长度
           sum = 0;
           do
           {
             String ctmp = "";
             do
             {
               len = ssl.Read(chunkedByte, 0, 1);
               ctmp += Encoding.UTF8.GetString(chunkedByte);

} while (ctmp.IndexOf(CT) == -1 && sw.ElapsedMilliseconds < timeout);

chunkedSize = Tools.convertToIntBy16(ctmp.Replace(CT, ""));

//chunked的结束0

是结束标志,单个chunked块
结束
             if (ctmp.Equals(CT))
             {
               continue;
             }
             if (chunkedSize == 0)
             {
               //结束了
               break;
             }
             int onechunkLen = 0;

while (onechunkLen < chunkedSize && sw.ElapsedMilliseconds < timeout)
             {
               len = ssl.Read(responseBody, sum, chunkedSize - onechunkLen);
               if (len > 0)
               {
                 onechunkLen += len;
                 sum += len;
               }
             }

//判断
           } while (sw.ElapsedMilliseconds < timeout);
         }
         //connection close方式或未知body长度
         else
         {
           while (sw.ElapsedMilliseconds < timeout)
           {
             if (clientSocket.Client.Poll(timeout, SelectMode.SelectRead))
             {
               if (clientSocket.Available > 0)
               {
                 len = ssl.Read(responseBody, sum, (1024 * 200) - sum);
                 if (len > 0)
                 {
                   sum += len;
                 }
               }
               else
               {
                 break;
               }
             }
           }
         }
         //判断是否gzip
         if (server.headers.ContainsKey(Content_Encoding))
         {
           server.body = unGzip(responseBody, sum, encod);
         }
         else
         {
           server.body = encod.GetString(responseBody, 0, sum);
         }
       }

}
     catch (Exception e)
     {
       Exception ee = new Exception("HTTPS发包错误!错误消息:" + e.Message + "----发包编号:" + index);
       throw ee;
     }
     finally
     {
       sw.Stop();
       server.length = sum;
       server.runTime = (int)sw.ElapsedMilliseconds;

if (clientSocket != null)
       {
         clientSocket.Close();
       }
     }
     return server;

}

public static String unGzip(byte[] data, int len, Encoding encoding)
   {

String str = "";
     MemoryStream ms = new MemoryStream(data, 0, len);
     GZipStream gs = new GZipStream(ms, CompressionMode.Decompress);
     MemoryStream outbuf = new MemoryStream();
     byte[] block = new byte[1024];

try
     {

while (true)
       {
         int bytesRead = gs.Read(block, 0, block.Length);
         if (bytesRead <= 0)
         {
           break;
         }
         else
         {
           outbuf.Write(block, 0, bytesRead);
         }
       }
       str = encoding.GetString(outbuf.ToArray());
     }
     catch (Exception e)
     {
       Tools.SysLog("解压Gzip发生异常----" + e.Message);
     }
     finally
     {
       outbuf.Close();
       gs.Close();
       ms.Close();

}
     return str;

}
   public static String getHTMLEncoding(String header, String body)
   {
     if (String.IsNullOrEmpty(header) && String.IsNullOrEmpty(body))
     {
       return "";
     }
     body = body.ToUpper();
     Match m = Regex.Match(header, @"charsets*=s*""?(?<charset>[^""]*)", RegexOptions.IgnoreCase);
     if (m.Success)
     {
       return m.Groups["charset"].Value.ToUpper();
     }
     else
     {
       if (String.IsNullOrEmpty(body))
       {
         return "";
       }
       m = Regex.Match(body, @"charsets*=s*""?(?<charset>[^""]*)", RegexOptions.IgnoreCase);
       if (m.Success)
       {
         return m.Groups["charset"].Value.ToUpper();
       }
     }
     return "";
   }
 }
}
0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com