2009-02-07 20 views
10

我試圖取代這個:C#中的套接字:如何獲取響應流?

void ProcessRequest(object listenerContext) 
{ 
    var context = (HttpListenerContext)listenerContext; 
    Uri URL = new Uri(context.Request.RawUrl); 
    HttpWebRequest.DefaultWebProxy = null; 
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(URL); 
    httpWebRequest.Method = context.Request.HttpMethod; 
    httpWebRequest.Headers.Clear(); 
    if (context.Request.UserAgent != null) httpWebRequest.UserAgent = context.Request.UserAgent; 
    foreach (string headerKey in context.Request.Headers.AllKeys) 
    { 
     try { httpWebRequest.Headers.Set(headerKey, context.Request.Headers[headerKey]); } 
      catch (Exception) { } 
    } 

    using (HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse()) 
    { 
     Stream responseStream = httpWebResponse.GetResponseStream(); 
     if (httpWebResponse.ContentEncoding.ToLower().Contains("gzip")) 
      responseStream = new GZipStream(responseStream, CompressionMode.Decompress); 
     else if (httpWebResponse.ContentEncoding.ToLower().Contains("deflate")) 
       responseStream = new DeflateStream(responseStream, CompressionMode.Decompress); 

     MemoryStream memStream = new MemoryStream(); 

     byte[] respBuffer = new byte[4096]; 
     try 
     { 
      int bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length); 
      while (bytesRead > 0) 
      { 
       memStream.Write(respBuffer, 0, bytesRead); 
       bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length); 
      } 
     } 
     finally 
     { 
      responseStream.Close(); 
     } 

     byte[] msg = memStream.ToArray(); 

     context.Response.ContentLength64 = msg.Length; 
     using (Stream strOut = context.Response.OutputStream) 
     { 
      strOut.Write(msg, 0, msg.Length); 
     } 
    } 
    catch (Exception ex) 
    { 
     // Some error handling 
    } 
} 

與插座。這是我到目前爲止有:

void ProcessRequest(object listenerContext) 
{ 
    HttpListenerContext context = (HttpListenerContext)listenerContext; 
    Uri URL = new Uri(context.Request.RawUrl); 
    string getString = string.Format("GET {0} HTTP/1.1\r\nHost: {1}\r\nAccept-Encoding: gzip\r\n\r\n", 
       context.Request.Url.PathAndQuery, 
       context.Request.UserHostName); 

    Socket socket = null; 

    string[] hostAndPort; 
    if (context.Request.UserHostName.Contains(":")) 
    { 
     hostAndPort = context.Request.UserHostName.Split(':'); 
    } 
    else 
    { 
     hostAndPort = new string[] { context.Request.UserHostName, "80" }; 
    } 

    IPHostEntry ipAddress = Dns.GetHostEntry(hostAndPort[0]); 
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse(ipAddress.AddressList[0].ToString()), int.Parse(hostAndPort[1])); 
    socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
    socket.Connect(ip); 

開始新的CODE

Encoding ASCII = Encoding.ASCII; 
Byte[] byteGetString = ASCII.GetBytes(getString); 
Byte[] receiveByte = new Byte[256]; 
string response = string.Empty; 
socket.Send(byteGetString, byteGetString.Length, 0); 
Int32 bytes = socket.Receive(receiveByte, receiveByte.Length, 0); 
response += ASCII.GetString(receiveByte, 0, bytes); 
while (bytes > 0) 
{ 
bytes = socket.Receive(receiveByte, receiveByte.Length, 0); 
strPage = strPage + ASCII.GetString(receiveByte, 0, bytes); 
} 
socket.Close(); 

string separator = "\r\n\r\n"; 
string header = strPage.Substring(0,strPage.IndexOf(separator)); 
string content = strPage.Remove(0, strPage.IndexOf(separator) + 4); 

byte[] byteResponse = ASCII.GetBytes(content); 
context.Response.ContentLength64 = byteResponse .Length; 
context.Response.OutputStream.Write(byteResponse , 0, byteResponse .Length); 
context.Response.OutputStream.Close(); 

END NEW CODE

連接到插座後,我不知道怎麼弄的流響應解壓縮,併發送回context.Response.OutputStream

任何幫助將不勝感激。 謝謝。 乾杯。

編輯2: 這個編輯現在似乎工作正常(至少與HttpWebRequest相同)。你在這裏找到任何錯誤嗎?

編輯3: 誤報...仍不能得到這個工作

編輯4: 我需要添加以下行斯科特的代碼...因爲不是總是第以reponseStream的字節爲gzip幻數。 該序列似乎是:0x0a(10),0x1f(31),0x8b(139)。最後兩個是gzip魔術數字。第一個數字總是在我的測試中。

if (contentEncoding.Equals("gzip")) 
{ 
    int magicNumber = 0; 
    while (magicNumber != 10) 
     magicNumber = responseStream.ReadByte(); 
    responseStream = new GZipStream(responseStream, CompressionMode.Decompress); 
} 
+0

@Matias:我必須問,你爲什麼要這麼做?你將花費很多的開銷來複制HttpWebRequest和HttpWebResponse已經爲你做的事情。 – casperOne 2009-02-07 15:29:02

+0

答案就在這裏:http://stackoverflow.com/questions/521977/is-it-possible-to-change-headers-order-using-httpwebrequest – 2009-02-07 15:51:56

回答

11

這裏有一些代碼適合我。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Net; 
using System.Net.Sockets; 
using System.Text; 
using System.IO.Compression; 

namespace HttpUsingSockets { 
    public class Program { 
     private static readonly Encoding DefaultEncoding = Encoding.ASCII; 
     private static readonly byte[] LineTerminator = new byte[] { 13, 10 }; 

     public static void Main(string[] args) { 
      var host = "stackoverflow.com"; 
      var url = "https://stackoverflow.com/questions/523930/sockets-in-c-how-to-get-the-response-stream"; 

      IPHostEntry ipAddress = Dns.GetHostEntry(host); 
      var ip = new IPEndPoint(ipAddress.AddressList[0], 80); 
      using (var socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) { 
       socket.Connect(ip); 
       using (var n = new NetworkStream(socket)) { 
        SendRequest(n, new[] {"GET " + url + " HTTP/1.1", "Host: " + host, "Connection: Close", "Accept-Encoding: gzip"}); 

        var headers = new Dictionary<string, string>(); 
        while (true) { 
         var line = ReadLine(n); 
         if (line.Length == 0) { 
          break; 
         } 
         int index = line.IndexOf(':'); 
         headers.Add(line.Substring(0, index), line.Substring(index + 2)); 
        } 

        string contentEncoding; 
        if (headers.TryGetValue("Content-Encoding", out contentEncoding)) { 
         Stream responseStream = n; 
         if (contentEncoding.Equals("gzip")) { 
          responseStream = new GZipStream(responseStream, CompressionMode.Decompress); 
         } 
         else if (contentEncoding.Equals("deflate")) { 
          responseStream = new DeflateStream(responseStream, CompressionMode.Decompress); 
         } 

         var memStream = new MemoryStream(); 

         var respBuffer = new byte[4096]; 
         try { 
          int bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length); 
          while (bytesRead > 0) { 
           memStream.Write(respBuffer, 0, bytesRead); 
           bytesRead = responseStream.Read(respBuffer, 0, respBuffer.Length); 
          } 
         } 
         finally { 
          responseStream.Close(); 
         } 

         var body = DefaultEncoding.GetString(memStream.ToArray()); 
         Console.WriteLine(body); 
        } 
        else { 
         while (true) { 
          var line = ReadLine(n); 
          if (line == null) { 
           break; 
          } 
          Console.WriteLine(line); 
         } 
        } 
       } 
      } 
     } 

     static void SendRequest(Stream stream, IEnumerable<string> request) { 
      foreach (var r in request) { 
       var data = DefaultEncoding.GetBytes(r); 
       stream.Write(data, 0, data.Length); 
       stream.Write(LineTerminator, 0, 2); 
      } 
      stream.Write(LineTerminator, 0, 2); 
      // Eat response 
      var response = ReadLine(stream); 
     } 

     static string ReadLine(Stream stream) { 
      var lineBuffer = new List<byte>(); 
      while (true) { 
       int b = stream.ReadByte(); 
       if (b == -1) { 
        return null; 
       } 
       if (b == 10) { 
        break; 
       } 
       if (b != 13) { 
        lineBuffer.Add((byte)b); 
       } 
      } 
      return DefaultEncoding.GetString(lineBuffer.ToArray()); 
     } 
    } 
} 

你可以用這個代替Socket/NetworkStream並保存一些工作。

using (var client = new TcpClient(host, 80)) { 
     using (var n = client.GetStream()) { 
    } 
} 
4

根據定義,套接字是訪問網絡的低級別。您甚至可以使用套接字使用數據報協議。在這種情況下,一個流是完全沒有意義的。

雖然我不確定你爲什麼要做HttpWebRequest很容易完成的事情,但是要使用發送/接收方法來讀/寫數據到套接字。如果你想擁有一個像訪問一個TCP套接字的流,你應該使用TcpClient/TcpListener類來封裝一個套接字併爲它提供一個網絡流。

3

還有一個將Socket作爲參數的NetworkStream類。 ;)

相關問題