2010-08-08 23 views
0

Donc, pour un peu d'arrière-plan: Cette classe est créée pour accepter et répondre aux appels effectués à distance dans un format HTTP. Le problème est lorsque la méthode de la demande est POST, parfois la demande est traitée correctement, mais la plupart du temps la classe finit par être irresponsable. En outre, les lignes "Debug1" et "Debug2" ne sont jamais écrites sur la console, même lorsque la requête est traitée correctement. La ligne "Debug3" n'apparaît que lorsque la requête est traitée correctement.Comportement étrange: TcpListener

Je sais que cela aura probablement l'air désordonné, C# est seulement un passe-temps pour moi, et j'apprends :) Merci d'avoir passé du temps à parcourir ce code!

Voici le code:

class WebServer 
{ 
    private TcpListener myListener; 

    public WebServer(int port) 
    { 
     //Threading the listener 
     try 
     { 
      myListener = new TcpListener(IPAddress.Any, port) ; 
      myListener.Start(); 

      Thread th = new Thread(new ThreadStart(StartListen)); 
      th.Start() ; 
     } 
     catch(Exception e) 
     { 
      Logs.Add("WebServer|An Exception Occurred while Listening :" +e.ToString()); 
     } 
    } 
    private void StartListen() 
    { 
     int iStartPos = 0; 
     string sHttpVersion; 
     string sResponse = ""; 
     string sCode = " 200 OK"; 

     while(true) 
     { 
      //Accept a new connection 
      Socket mySocket = myListener.AcceptSocket(); 
      if(mySocket.Connected) 
      { 
       Byte[] bReceive = new Byte[1024]; 
       int i = mySocket.Receive(bReceive,bReceive.Length,SocketFlags.None); 
       string sBuffer = Encoding.ASCII.GetString(bReceive).TrimEnd('\0'); 

       iStartPos = sBuffer.IndexOf("HTTP",1); 
       sHttpVersion = sBuffer.Substring(iStartPos,8); //http version (ex: "HTTP/1.1") 

       if (sBuffer.StartsWith("GET/")) 
       { 
        Logs.Add("WebServer|Connected:" + mySocket.RemoteEndPoint.ToString()); 
        sResponse = ArrayToJson(); 
       } 
       else if (sBuffer.StartsWith("POST")) 
       { 
        Console.WriteLine("Debug1"); 

        //This is a POST request, so more data is waiting to be retreived... 
        bReceive = new Byte[2048]; 
        i = mySocket.Receive(bReceive,bReceive.Length,SocketFlags.None); 
        sBuffer = Encoding.ASCII.GetString(bReceive).TrimEnd('\0'); 

        Console.WriteLine("Debug2"); 

        //Parsing the request 
        string[] sParams = sBuffer.Split(','); 
        Console.WriteLine(sParams.Length); 
        Console.WriteLine("Debug3: {0} - {1} - {2} - {3} - {4}", sParams[0], sParams[1], sParams[2], sParams[3], sParams[4]); 

        //I do what needs to be done here 

        Logs.Add("WebServer|BotStartRequest:" + mySocket.RemoteEndPoint.ToString()); 
        sResponse = "Accepted"; 
       } 

       //Sending response and closing socket 
       SendHeader(sHttpVersion, "text/html", sResponse.Length, sCode, ref mySocket); 
       SendToBrowser(sResponse, ref mySocket); 
       mySocket.Close(); 
      } 
     } 
    } 
} 

}

+0

Avez-vous essayé d'augmenter la taille du tampon de réception? Si le navigateur envoie> 2048 octets, je suppose que vous pourriez vous retrouver dans une situation où vous avez seulement lu une partie de la demande, et la conversation serait laissée dans un état «douteux». –

+0

Je doute que ce soit le problème parce que je n'ai jamais vu ce corps se rapprocher de 2048 octets. J'ai aussi fait mes tests avec seulement quelques requets différents, la plupart d'entre eux ont exactement le même corps, et ça fonctionne encore aléatoirement ... – Ben

+0

Ceci est porté C++, pas C# idiomatique, donc cela rend le débogage très difficile. Vous avez besoin d'un try/catch + log dans votre boucle while pour commencer à comprendre cela. La façon dont vous gérez les tampons est inefficace et probablement la source de vos problèmes. –

Répondre

4

La mise en œuvre HTTP/1.1 n'est pas une tâche simple. Le protocole de base semble assez simple, mais il est vraiment difficile d'obtenir une implémentation minimale du serveur: Vous devez au moins penser aux connexions persistantes, dans le cas du POST de l'en-tête Expect: 100-continue, correctement l'en-tête , et beaucoup plus.

Je vous recommande fortement d'examiner les bibliothèques/codes existants. Par exemple, la classe HttpListener est intégrée au .NET Framework et fournit probablement déjà tout ce dont vous aurez besoin.

Si vous voulez vraiment implémenter un serveur à partir de zéro, jetez un oeil à Microsoft Cassini, un serveur HTTP simple écrit en C# sous licence Ms-PL.

+0

Merci, si je ne peux pas le faire fonctionner, c'est probablement ce que je vais finir par faire. Mais c'est parce que mon utilisation est si simple que je voulais la faire mienne et ne pas utiliser une bibliothèque existante. – Ben