2009-02-07 14 views
10

estoy tratando de reemplazar este:Enchufes en C#: ¿Cómo obtener la secuencia de respuesta?

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

con tomas. Esto es lo que tengo hasta ahora:

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

COMENZAR NUEVO CÓDIGO

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

FIN NUEVO CÓDIGO

Después de conectarse a la toma de corriente no sé cómo obtener el Transmita la respuesta para descomprimir y envíe de vuelta al context.Response.OutputStream

Cualquier ayuda será apreciada. Gracias. Saludos.

EDIT 2: Con esta edición ahora parece estar funcionando bien (al igual que HttpWebRequest al menos). ¿Encuentra algún error aquí?

Datos 3: Falsa alarma ... ¿Todavía no puede conseguir este funcionamiento

EDITAR 4: que tenía que añadir las siguientes líneas al código de Scott ... porque no siempre el primero a bytes de reponseStream son el número mágico de gzip. La secuencia parece ser: 0x0a (10), 0x1f (31), 0x8b (139). Los dos últimos son el número mágico de gzip. El primer número siempre fue antes en mis pruebas.

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

@Matias: Tengo que preguntar, ¿por qué quieres hacer esto? Va a gastar tanto sobrecarga duplicando lo que HttpWebRequest y HttpWebResponse ya hacen por usted. – casperOne

+0

La respuesta para eso está aquí: http://stackoverflow.com/questions/521977/is-it-possible-to-change-headers-order-using-httpwebrequest –

Respuesta

11

Aquí hay un código que funciona para mí.

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

Puede sustituir esto por el Socket/NetworkStream y ahorrar un poco de trabajo.

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

¡eh !, gracias por su respuesta !!!! pero recibo una excepción: InvalidDataException: El número mágico en el encabezado GZip no es correcto. Asegúrate de pasar en una transmisión GZip. El problema parece estar en esta línea: int bytesRead = responseStream.Read (respBuffer, 0, respBuffer.Length); ¿Alguna idea? –

+0

Ejecútelo en depuración y compruebe que los primeros dos bytes sean 0x1f 0x8b (el número mágico de gzip), tal vez haya una línea adicional o prefijo o algo. – Scott

+0

Gracias por responder. He añadido algunas líneas después de "if (contentEncoding.Equals (" gzip ")) {" para buscar el comienzo del número mágico de gzip. Está en mi primera publicación. ¡Atentamente! –

4

Enchufe, por definición, es el nivel bajo para acceder a la red. Incluso puede usar protocolos de datagramas con un socket. En ese caso, una transmisión no tiene ningún sentido.

Si bien no estoy seguro de por qué está haciendo lo que HttpWebRequest logra fácilmente, para leer/escribir datos en un socket, utiliza los métodos de Enviar/Recibir. Si desea tener un acceso de flujo continuo a un socket TCP, debe usar las clases TcpClient/TcpListener que envuelven un socket y le proporcionan una secuencia de red.

3

También existe la clase NetworkStream que toma un zócalo como parámetro. ;)

Cuestiones relacionadas