2009-02-07 6 views
10

Ich versuche, diese zu ersetzen:Sockets in C#: Wie bekomme ich den Antwort-Stream?

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 
    } 
} 

mit Steckdosen. Dies ist, was habe ich bisher:

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 NEU BEGIN

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

an die Buchse Nach Anschluss ich weiß nicht, wie das bekommen Stream-Antwort zum Dekomprimieren und zurücksenden an context.Response.OutputStream

Jede Hilfe wird geschätzt. Danke. Prost.

EDIT 2: Mit dieser Bearbeitung scheint jetzt gut zu funktionieren (mindestens wie HttpWebRequest). Findest du hier einen Fehler?

EDIT 3: Fehlalarm ... immer noch nicht diese Arbeit

EDIT 4: Ich brauchte die folgenden Zeilen zu Scotts Code hinzuzufügen ... weil nicht immer die erste zu Bytes von AntwortStream sind die gzip magische Zahl. Die Reihenfolge scheint zu sein: 0x0a (10), 0x1f (31), 0x8b (139). Die letzten beiden sind die gzip magische Zahl. Die erste Nummer war bei meinen Tests immer vorher.

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

@Matias: Ich muss fragen, warum willst du das tun? Sie werden so viel Overhead ausgeben, was HttpWebRequest und HttpWebResponse bereits für Sie tun. – casperOne

+0

Die Antwort dafür ist hier: http://stackoverflow.com/questions/521977/is-it-possible-to-change-headers-order-using-httpwebrequest –

Antwort

11

Hier ist ein Code, der für mich funktioniert.

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()); 
     } 
    } 
} 

Sie könnten dies für den Socket/NetworkStream ersetzen und ein wenig Arbeit sparen.

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

hey !, danke für Ihre Antwort! aber ich bekomme eine Ausnahme: InvalidDataException: Die magische Zahl in GZip-Header ist nicht korrekt. Stellen Sie sicher, dass Sie einen GZip-Stream übergeben. Das Problem scheint in dieser Zeile zu sein: int bytesRead = responseStream.Read (respBuffer, 0, respBuffer.Length); Irgendwelche Ideen? –

+0

Führen Sie es in Debug und überprüfen Sie, dass die ersten paar Bytes 0x1f 0x8b (die gzip magische Zahl) sind, vielleicht gibt es eine zusätzliche Linie oder ein Präfix oder etwas. – Scott

+0

Danke für die Antwort. Ich habe ein paar Zeilen nach "if (contentEncoding.Equals (" gzip ")) {" eingefügt, um den Beginn der gzip-Magic-Nummer zu suchen. Es ist auf meinem ersten Beitrag. Freundliche Grüße! –

4

Sockel, per Definition, ist die niedrige Ebene für den Zugriff auf das Netzwerk. Sie können sogar Datagrammprotokolle mit einem Socket verwenden. In diesem Fall macht ein Stream überhaupt keinen Sinn.

Während ich bin nicht sicher, warum tun Sie, was HttpWebRequest einfach zu erreichen, um Daten zu einem Socket zu lesen/schreiben, verwenden Sie die Send/Receive-Methoden. Wenn Sie einen Stream wie den Zugriff auf einen TCP-Socket haben möchten, sollten Sie die TcpClient/TcpListener-Klassen verwenden, die einen Socket umschließen und einen Netzwerkstream dafür bereitstellen.

3

Es gibt auch die NetworkStream-Klasse, die einen Socket als Parameter verwendet. ;)