2015-05-20 5 views
6

में HTTP या HTTPS पर अनुरोध आता है या नहीं, मेरे पास बहु थ्रेड एसिंक सॉकेट श्रोता है। मैं यह जांचना चाहता हूं कि अनुरोध सुरक्षित है या नहीं। लेकिन मैं इसे स्वीकार करना चाहता हूं कि AcceptCallBack विधि में GetCackBack प्राप्त नहीं है।सॉकेट श्रोता

मैं ऐसा इसलिए करूँगा क्योंकि मैं चाहता हूं कि मेरा कोड HTTP और HTTPS दोनों के लिए काम करे। अगर अनुरोध एचटीटीपीएस से आता है तो मैं सिर्फ कच्चे सॉकेट के बजाय एक प्रमाणित एसएसएलस्ट्रीम के साथ जाऊंगा।

using System; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 
using System.Text; 

namespace LearnRequestType 
{ 
    class StackOverFlow 
    { 
     private static readonly ManualResetEvent _manualResetEvent = new ManualResetEvent(false); 

     private void StartListening() 
     { 
      IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9002); 

      if (localEndPoint != null) 
      { 
       Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

       if (listener != null) 
       { 
        listener.Bind(localEndPoint); 
        listener.Listen(10); 

        Console.WriteLine("Socket listener is running..."); 

        listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
       } 
      } 
     } 

     private void AcceptCallback(IAsyncResult ar) 
     { 
      _manualResetEvent.Set(); 

      Socket listener = (Socket)ar.AsyncState; 

      Socket handler = listener.EndAccept(ar); 

      StateObject state = new StateObject(); 
      state.workSocket = handler; 

      // I want to understand if request comes from HTTP or HTTPS before this line. 
      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 

      listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
     } 

     private void ReceiveCallback(IAsyncResult result) 
     { 
      StateObject state = (StateObject)result.AsyncState; 
      Socket handler = state.workSocket; 

      string clientIP = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString(); 

      int numBytesReceived = handler.EndReceive(result); 

      if (!handler.Connected) 
      { 
       handler.Close(); 
       return; 
      } 

      // Read incoming data... 
      if (numBytesReceived > 0) 
      { 
       state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, numBytesReceived)); 

       // Read incoming data line by line. 
       string[] lines = state.sb.ToString().Split('\n'); 

       if (lines[lines.Length - 1] == "<EOF>") 
       { 
        // We received all data. Do something... 

       } 
       else 
       { 
        // We didn't receive all data. Continue reading... 
        handler.BeginReceive(state.buffer, 0, state.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), state); 
       } 
      } 
     } 
    } 
} 

public class StateObject 
{ 
    public Socket workSocket = null; 
    public const int BufferSize = 256; 
    public byte[] buffer = new byte[BufferSize]; 
    public StringBuilder sb = new StringBuilder(); 
} 

अगर मैं उस तरह विधि और StateObject कक्षा AcceptCallBack बदलने:

यहाँ मेरी कोड है

private void AcceptCallback(IAsyncResult ar) 
{ 
    _manualResetEvent.Set(); 

    Socket listener = (Socket)ar.AsyncState; 

    Socket handler = listener.EndAccept(ar); 

    try 
    { 
     sslStream = new SslStream(new NetworkStream(handler, true)); 

     // try to authenticate 
     sslStream.AuthenticateAsServer(_cert, false, System.Security.Authentication.SslProtocols.Tls, true); 

     state.workStream = sslStream; 
     state.workStream.ReadTimeout = 100000; 
     state.workStream.WriteTimeout = 100000; 

     if (state.workStream.IsAuthenticated) 
     { 
      state.workStream.BeginRead(state.buffer, 0, StateObject.BufferSize, ReceiveCallback, state); 
     } 
    } 
    catch (IOException ex) 
    { 
     // ıf we get handshake failed due to an unexpected packet format, this means incoming data is not HTTPS 
     // Continue with socket not sslstream 
     state.workSocket = handler; 
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 
    } 

    StateObject state = new StateObject(); 
    state.workStream = handler; 

    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 

    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
} 

public class StateObject 
{ 
    public Socket workSocket = null; 
    public SslStream workStream = null; 
    public const int BufferSize = 1024; 
    public byte[] buffer = new byte[BufferSize]; 
    public StringBuilder sb = new StringBuilder(); 
} 

अगर आने वाले डेटा प्रकार HTTP या HTTPS है मैं तय कर सकते हैं लेकिन अगर यह है HTTP इसे हर बार कैच ब्लॉक द्वारा संभाला जाएगा ताकि यह एप्लिकेशन प्रदर्शन को कम कर दे।

क्या कोई और तरीका है?

उत्तर

4

यदि मैं सही ढंग से समझ गया, तो आपके पास एक एकल बंदरगाह है जहां क्लाइंट कनेक्ट करने के लिए HTTP या HTTPS का उपयोग कर सकता है और आप तुरंत जानना चाहते हैं कि किसी भी डेटा को स्थानांतरित करने से पहले अनुरोध कैसे किया गया था।

ग्राहक से डेटा प्राप्त करने से पहले इसे जानने का कोई तरीका नहीं है। HTTP और HTTPS टीसीपी के शीर्ष पर प्रोटोकॉल हैं, वे कम प्रोटोकॉल स्तर पर काम नहीं करते हैं, इसलिए कोई ध्वज या कुछ भी नहीं है जो कह सकता है कि कौन सा प्रोटोकॉल उपयोग किया जाता है। इसके अलावा एचटीटीपीएस एक सामान्य HTTP स्ट्रीम है जो टीएलएस/एसएसएल स्ट्रीम में लपेटा जाता है।

आपको डेटा को पढ़ना होगा और उस प्रोटोकॉल का उपयोग करने के आधार पर निर्धारित करना होगा। या आपके पास HTTP और HTTPS के लिए अलग-अलग बंदरगाह हैं, जो यह मामूली बना देगा। अगर यह TLS/SSL आप कर सकते थे झांकना कुछ बाइट्स और देखते हैं कि में आता है

पता लगाने के लिए। The TLS specification कहते ग्राहक हैलो पैकेट प्रोटोकॉल संस्करण है, जो दो uint8 रों के रूप में भेजा जाता है के साथ शुरू होता है। चूंकि एक HTTP अनुरोध में हमेशा क्रिया होती है, इसलिए आप आसानी से जांच सकते हैं कि पहले बाइट्स में से कुछ जोड़े हैं या नहीं और फिर SSLStream यदि यह नहीं है तो कोशिश करें।

यह भी ध्यान रखें कि यदि आप सॉकेट पर SSLStream शुरू करते हैं, तो यह सॉकेट से पढ़ सकता है, जो HTTP अनुरोध की शुरुआत का उपभोग करेगा और आप इसे सामान्य रूप से सामान्य रूप से संभाल नहीं सकते।

Socket handler = listener.EndAccept(ar); 
byte[] tmp = new byte[2]; 
handler.Receive(tmp, 0, 2, SocketFlags.Peek); 
if (!Char.IsLetter((char)tmp[0]) || !Char.IsLetter((char)tmp[1])) 
{ 
    // Doesn't start with letters, so most likely not HTTP 
} else { 
    // Starts with letters, should be HTTP 
} 

आप वास्तव में यह TLS/SSL है सुनिश्चित करने के लिए चाहते हैं, तो आप जांच कर सकता है this question on SO

+0

अपने जवाब के लिए धन्यवाद:

अपने इस तरह कॉलबैक उपयोग कुछ स्वीकार में तो

। असल में मैं जांच सकता हूं कि ऐसा करने से HTTP या HTTPS है या नहीं। मेरा संपादित प्रश्न देखें। लेकिन यहां समस्या पकड़ने की कोशिश है। –

+0

@ OrkunBekar इस बारे में जानकारी दी गई है कि यह कितना अच्छा अनुमान है कि यह HTTP है या नहीं। –

+0

मैं प्रोटोकॉल संस्करण कैसे देख सकता हूं? क्या यह AcceptCallBack विधि में किसी ऑब्जेक्ट के अंदर संग्रहीत है? मेरे पास इन दो uint8 मूल्य कहां होंगे? –