6

J'ai une application écrite en VB.NET (PAS asp.net, il s'agit d'une application console de Windows). J'essaie d'appeler une url (une page html) et de récupérer la réponse dans une chaîne. La réponse est JSON droite, pas de tags html que ce soit. Il s'ouvre avec { et se termine par }.Obtenir "connexion sous-jacente a été fermée" sur HttpWebRequest

Je crée l'objet HttpWebRequest correctement. Puis appelez req.GetResponse(). Dès que je fais cela, j'obtiens l'erreur The underlying connection was closed: The connection was closed unexpectedly. J'ai été googler et vérifier stackoverflow, et j'ai essayé tout ce que j'ai trouvé qui s'applique (beaucoup de choses à faire avec les configurations de service WCF, qui ne s'appliquent pas).

Voici mon code:

Public Function GetJSON(ByRef d As db.Device) As Boolean 
    Try 
     d.Url = "http://" & d.IpAddress & ini.doc.<svc>.<url>.Value 

     Dim req As HttpWebRequest = HttpWebRequest.Create(d.Url) 
     // req.Accept = "*/*" 
     // req.Timeout = 30000 
     // req.ReadWriteTimeout = 30000 
     // req.KeepAlive = False 
     // req.UseDefaultCredentials = True 
     // req.CachePolicy = HttpWebRequest.DefaultCachePolicy 
     // req.Proxy = HttpWebRequest.DefaultWebProxy 
     // req.ProtocolVersion = New System.Version(1, 0) 

     Dim rsp As HttpWebResponse = req.GetResponse() 

     Return True 
    Catch ex As Exception 
     Log(ex.Message) 
     Return False 
    Finally 
     rsp = Nothing 
     req = Nothing 
    End Try 
End Function 

Les lignes commentées (mauvais style de commentaire, mais si SO va l'analyser à droite) sont toutes les choses que je l'ai essayé jusqu'à présent basé sur ce que j'ai trouvé en ligne . Aucun d'eux ne l'a réparé. J'ai vérifié que l'URL en cours de construction est correcte; si j'appelle exactement la même URL dans mon navigateur, il me donne exactement la bonne réponse attendue.

J'ai essayé wiresharking ... et je vois les attendus réels, les données complètes reviennent dans la sortie de requin, puis quelques lignes, puis une ligne rouge qui dit: http > 51943 [RST] Seq=1607 Win=0 Len=0 qui est la dernière ligne pour apparaître avant .NET jette l'erreur.

J'ai aussi essayé d'allumer System.Net traçage/exploitation forestière par un poste ici sur le SO, et dans le fichier de sortie que je vois même, tous les données JSON attendues -t revenir, mais après il revient, il jette ces lignes dans le journal de trace .NET:

System.Net.Sockets Verbose: 0 : [7040] Exiting Socket#60467532::Receive() -> 1605#1605 
System.Net.Sockets Verbose: 0 : [7040] Socket#60467532::Receive() 
System.Net.Sockets Verbose: 0 : [7040] Data from Socket#60467532::Receive 
System.Net.Sockets Verbose: 0 : [7040] 00000000 :             : 
System.Net.Sockets Verbose: 0 : [7040] Exiting Socket#60467532::Receive() -> 0#0 
System.Net.Sockets Verbose: 0 : [7040] Socket#60467532::Dispose() 
System.Net Error: 0 : [7040] Exception in the HttpWebRequest#27806816:: - The underlying connection was closed: The connection was closed unexpectedly. 
System.Net Error: 0 : [7040] Exception in the HttpWebRequest#27806816::GetResponse - The underlying connection was closed: The connection was closed unexpectedly. 

Toutes les idées où aller pour essayer de comprendre cela? Nous lisons ces données à partir de certains capteurs de surveillance de l'environnement, et ils nous ont donné cette URL à utiliser.

Deux choses qui me suis vraiment et me confondre à ce sujet sont que
a) il fonctionne parfaitement bien quand appelé dans un navigateur
b) les deux WireShark et le traçage .NET montrent toutes les données réellement IS revenir, et le cadre est pour une raison quelconque, sauf après avoir reçu toutes les données!

Le WebException lui-même est très peu utilisé, comme InnerException est nulle et son statut dit juste « ConnectionClosed {8} »

Merci d'avance !!!

MISE À JOUR 08/18 1130: J'ai aussi essayé d'utiliser maintenant juste System.Net.WebRequest par opposition à HttpWebRequest. Cela n'a pas fait de différence non plus.

MISE À JOUR 08/18 1222: Je viens essayé passer mon code au lieu d'utiliser [Http]Web[Request|Response] à gradation un objet WebClient au lieu et en utilisant sa méthode DownloadString(). Ceci cependant aussi renvoie la même erreur exacte.

MISE À JOUR 08/18 1230: essayé d'utiliser My.Computer.Network.DownloadFile() - obtient également la même erreur fermée connexion.

+0

Voici un pastebin de ma complète network.log trace .NET fichier: http://pastebin.com/QfY05a11. Vous pouvez voir toutes les données JSON qui reviennent sur la ligne 41. – eidylon

+0

Voici un pastebin du journal de trafic Wireshark: http://pastebin.com/0hbEQerc. Vous pouvez voir les données à la ligne 607. – eidylon

Répondre

4

Pouvez-vous publier tout le contenu du journal de suivi sur pastebin.com et publier un lien ici?

Vous pourriez obtenir cette exception car le serveur peut dire dans l'en-tête "Content-Length" qu'il envoie N octets d'entité, mais qu'en réalité il envoie moins de N octets et ferme la connexion.

Réponse:

Merci pour les données. À partir de la trace tracelog et wireshark, il semble que le serveur n'envoie aucun en-tête de réponse et envoie directement les données. C'est une violation de protocole HTTP. C'est pourquoi le client lance l'exception.

+0

Cool site ... jamais vu auparavant. Va poster ces momentanément ... – eidylon

+0

Oui, à partir du tracelog, je peux voir que le serveur ne répond pas avec des en-têtes de réponse HTTP valide. Le serveur doit d'abord envoyer les en-têtes de réponse HTTP, puis envoyer la charge utile JSON. C'est le problème – feroze

+0

Il y a aussi un bug dans votre code. Vous ne disposez pas de l'objet HttpWebResponse que vous obtenez en appelant GetResponse(). Vous devez appeler Dispose() sur cet objet, sinon vous manquerez de connexions au serveur. – feroze

2

Voici comment je l'ai fait fonctionner ... Merci de feroze pour me pointer dans la bonne direction!
(points attribués)

Public Function GetJSON(ByRef d As db.Device) As Boolean 
    Try 
     Dim tcp = New TcpClient() 
     tcp.Connect(d.IpAddress, 80) 

     Dim ns = tcp.GetStream() 

     Dim req As Byte() = System.Text.Encoding.ASCII.GetBytes(
      "GET /getdata.htm HTTP/1.1" & vbCrLf & vbCrLf 
     ) 
     ns.Write(req, 0, req.Length) 

     Dim rsp(2048) As Byte, rcv As Integer 
     Do 
      rcv = ns.Read(rsp, 0, rsp.Length) 
      d.JSON &= System.Text.Encoding.ASCII.GetString(rsp, 0, rcv) 
     Loop Until rcv = 0 

     tcp.Close() 

     Return True 
    Catch ex As Exception 
     Log(ex.Message) 
     Return False 
    End Try 
End Function 
+1

'tcp.Close()' devrait être appelé de l'intérieur "finally", sinon il ne sera pas appelé s'il y a une exception avant l'appel '.Close()'. – sharptooth

+0

@sharptooth Bon point. – eidylon

1

Cela me aide. J'espère que cela aidera aussi quelqu'un. Juste après avoir créé l'objet HttpWebRequest, ajoutez cette ligne.

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;

Ce que cela signifie est spécifie la Secure Socket Layer (SSL) 3.0 comme protocole de sécurité

http://support.microsoft.com/kb/915599

0

Vérifiez la latence de la demande. S'il est plus que quelques ms alors il vaut la peine de désactiver l'algorithme Nagle

ServicePointManager.UseNagleAlgorithm = false; 
0

Je faisais la même question au sujet d'une demande sans corps. Dans mon cas, la définition de ContentLength à ZERO a résolu le problème.

0

Dans mon cas, le problème est que nous avons utilisé "http: // .." comme adresse de service au lieu de "https: //" ...