2017-10-08 16 views
0

Je crée une connexion TCP en C# à un flux mp3 en utilisant HTTP pour analyser une requête. Quand j'ouvre la connexion, je toujours ferme à l'aideTCPClient renvoie 400 la plupart du temps

tcpClient.GetStream().Close(); 
tcpClient.Close(); 

J'ai aussi essayé d'utiliser:

client.Client.Disconnect(false); 

Si je lance mon application à nouveau et re-connecter, je reçois 400 (Bad Request) et connection-close dans l'en-tête de réponse, même si je vois en utilisant "netstat" que la connexion n'existe plus. Ce est le code que j'ai jusqu'à présent:

string headers = new string [] { 
        "GET /stream HTTP/1.0", 
        "Host: sci.streamingmurah.com:8032", 
        "Connection: keep-alive", 
        "Accept-Encoding: identity;q=1, *;q=0", 
        "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", 
        "Accept: */*", 
        "Referer: 82.XX.XX.XX", 
        "Accept-Language: en-US,en;q=0.8,he;q=0.6" 
      }; 
try 
{ 
    using (TcpClient client = new TcpClient()) 
    { 
     client.SendTimeout = 5000; 
     client.ReceiveTimeout = 5000; 
     client.Connect(host, port); 
     using (NetworkStream ns = client.GetStream()) 
     { 

      foreach (string requestHeader in headers) 
      { 
       Debug.WriteLine("Request Header: " + requestHeader); 

       byte[] headerBytes = Encoding.ASCII.GetBytes(requestHeader); 
       ns.Write(headerBytes, 0, headerBytes.Length); 
       ns.WriteByte(13); 
       ns.WriteByte(10); 
      } 

      ns.WriteByte(13); 
      ns.WriteByte(10); 

      List<string> responseHeaders = new List<string>(); 

      string responseHeader; 
      while (Utils.ReadLine(ns, Encoding.ASCII, out responseHeader) && responseHeader.Length > 0) 
      { 
       responseHeaders.Add(responseHeader); 
      } 
      //Response headers contains 
      if (responseHeaders.Count == 0) 
      { 
       traceInfo.AddLine(TraceInfo.EntryKind.Alert, "Response is empty"); 
       client.GetStream().Close(); 
       client.Close(); 
       //client.Client.Disconnect(false); 
       return null; 
      } 

      Playable pl = HandleResponse(responseHeaders.ToArray(), ns); 
      client.GetStream().Close(); 
      client.Close(); 
      return pl; 
     } 
    } 
} 
catch (Exception e) 
{ 
    traceInfo.AddLine(TraceInfo.EntryKind.Alert, String.Format("Exception: {0}", e.Message)); 
} 

return null; 

Bien sûr - si je lance le flux dans Chrome, cela fonctionne toujours. Donc, quelque chose que je fais doit être faux. Une idée?

Merci

+0

Peut-être parce que 'Content-Length' est manquant. (Pourquoi n'utilisez-vous pas simplement WebClient ou HttpClient) –

+1

@ L.B: Ceci est une requête GET. Il n'a pas de contenu et donc aucun en-tête Content-Length n'est utilisé (le navigateur ne le fait pas non plus). –

Répondre

1

Vous envoyez le contenu de chaque ligne et chaque \r et \n chacun dans son propre Write. De cette façon, la requête peut être répartie sur plusieurs paquets TCP, ce qui n'est pas un problème en théorie, puisque TCP est juste un flux de données sans limites de message implicites. Mais, certaines expériences montrent que c'est en fait un problème dans ce cas: Si on envoie la requête à l'intérieur d'une seule écriture (ce qui aboutit à un seul paquet) cela fonctionnera, s'il est réparti sur plusieurs écritures au 400 Bad Request. Je suppose qu'il existe une certaine protection devant le serveur Web ou dans le serveur qui tente de détecter les attaques DOS comme Slowloris où l'attaquant étale la requête HTTP sur plusieurs paquets avec beaucoup de retard entre les deux. Bien que vous n'effectuiez pas une telle attaque, le comportement provoqué par votre code (demande répartie sur plusieurs paquets) peut déclencher cette détection DOS qui rejette alors la demande plus tôt. Le correctif serait de ne pas écrire immédiatement chaque partie de l'en-tête de la requête dans le socket, mais de rassembler tout ce qui se trouve dans un tampon interne et d'envoyer ce tampon à l'intérieur d'une seule écriture dans le socket.

+0

C'était une réponse parfaite! J'ai ajouté tous les en-têtes dans un StringBuilder, puis j'ai tout écrit en même temps. Cela a très bien fonctionné. Je vous remercie!! – Basilf