2009-02-07 35 views
10

Tôi đang cố gắng thay thế điều này:Ổ cắm trong C#: Cách nhận luồng phản hồi?

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

có ổ cắm. Đây là những gì tôi có cho đến nay:

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

BEGIN MÃ MỚI

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 MỚI MÃ

Sau khi kết nối với ổ cắm Tôi không biết làm thế nào để có được Phản hồi luồng để giải nén và gửi lại cho ngữ cảnh.Response.OutputStream

Mọi trợ giúp sẽ được đánh giá cao. Cảm ơn. Chúc mừng.

CHỈNH SỬA 2: Với bản chỉnh sửa này hiện có vẻ hoạt động tốt (giống như HttpWebRequest ít nhất). Bạn có tìm thấy lỗi nào ở đây không?

EDIT 3: False báo động ... Vẫn không thể có được điều này làm việc

EDIT 4: tôi cần phải thêm dòng sau vào mã của Scott ... bởi vì không phải lúc nào cũng là người đầu tiên tới byte của reponseStream là số ma thuật gzip. Trình tự có vẻ là: 0x0a (10), 0x1f (31), 0x8b (139). Hai số cuối cùng là số ma thuật gzip. Con số đầu tiên luôn luôn là trước trong các bài kiểm tra của tôi.

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

@Matias: Tôi phải hỏi, tại sao bạn muốn làm điều này? Bạn sẽ chi tiêu quá nhiều vào việc sao chép những gì HttpWebRequest và HttpWebResponse đã làm cho bạn. – casperOne

+0

Câu trả lời cho điều đó là ở đây: http://stackoverflow.com/questions/521977/is-it-possible-to-change-headers-order-using-httpwebrequest –

Trả lời

11

Đây là một số mã phù hợp với tôi.

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

Bạn có thể thay thế điều này cho Socket/NetworkStream và lưu một chút công việc.

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

hey !, cảm ơn câu trả lời của bạn !!!! nhưng tôi nhận được Ngoại lệ: InvalidDataException: Số ma thuật trong tiêu đề GZip không chính xác. Đảm bảo bạn đang truyền trong luồng GZip. Sự cố dường như nằm trong dòng này: int bytesRead = responseStream.Read (respBuffer, 0, respBuffer.Length); Bất kỳ ý tưởng nào? –

+0

Chạy nó trong gỡ lỗi và kiểm tra xem cặp byte đầu tiên là 0x1f 0x8b (số ma thuật gzip), có thể có thêm một dòng hoặc tiền tố hoặc cái gì đó. – Scott

+0

Cảm ơn bạn đã trả lời. Tôi đã thêm một vài dòng sau "if (contentEncoding.Equals (" gzip ")) {" để tìm kiếm sự bắt đầu của số ma thuật gzip. Đó là bài đăng đầu tiên của tôi. Trân trọng! –

4

Ổ cắm theo định nghĩa là cấp thấp để truy cập mạng. Bạn thậm chí có thể sử dụng các giao thức datagram với một socket. Trong trường hợp đó, một luồng không có ý nghĩa gì cả.

Trong khi tôi không chắc chắn tại sao bạn làm những gì HttpWebRequest dễ dàng thực hiện, để đọc/ghi dữ liệu vào ổ cắm, bạn sử dụng các phương thức Gửi/nhận. Nếu bạn muốn có một luồng như truy cập vào một socket TCP, bạn nên sử dụng các lớp TcpClient/TcpListener bao bọc một socket và cung cấp một luồng mạng cho nó.

3

Ngoài ra còn có lớp NetworkStream lấy Socket làm tham số. ;)

Các vấn đề liên quan