2010-06-29 3 views
2

J'ai un système de communication basé sur TcpClient, et il fonctionne très bien, sauf quand il fait HTTPS à une adresse IP particulière. Ensuite, il commence à échouer.Comment faire HTTPS avec TcpClient comme le fait HttpWebRequest?

En utilisant un navigateur ou HttpWebRequest, je n'ai aucun problème à faire HTTPS à cette adresse IP.

J'ai créé un programme de test pour réduire mon problème à son essence de base, vous pouvez avoir un coup d'oeil ici si vous voulez: TestViaTcp

Ce programme de test fonctionne parfaitement pour HTTP de base à la même adresse IP , il produit toujours une réponse réussie à la demande. Je le mets en boucle, je le déclenche avec une pression sur une touche, il continuera à fonctionner toute la journée. Dès que je bascule le HTTPS, je reçois un motif récurrent. Ça marchera, et ça ne marchera pas, le succès sera suivi par l'échec suivi par le succès tout au long de la journée.

L'échec particulier, je continue à obtenir est celui-ci:

{"Authentication failed because the remote party has closed the transport stream."} 
    [System.IO.IOException]: {"Authentication failed because the remote party has closed the transport stream."} 
    Data: {System.Collections.ListDictionaryInternal} 
    HelpLink: null 
    InnerException: null 
    Message: "Authentication failed because the remote party has closed the transport stream." 
    Source: "System" 
    TargetSite: {Void StartReadFrame(Byte[], Int32, System.Net.AsyncProtocolRequest)} 

Et voici la trace de la pile attachée à ce:

at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) 
    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) 
    at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest) 
    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest) 
    at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) 
    at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult) 
    at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation) 
    at DeriveClassNameSpace.Services.Web.TcpMessaging.TestViaTcp(IPEndPoint endpoint, String auth, Boolean useSSL) 

HttpWebRequest et le navigateur sont tous les deux (IIRC) en utilisant les bibliothèques Win32 pour gérer la communication de va-et-vient, alors que TcpClient est (AFAIK) en utilisant la classe .net Socket gérée, donc je suis sûr qu'il y a une grande différence entre eux. J'ai besoin de faire cela avec TcpClient, donc malheureusement je ne peux pas simplement "utiliser HttpWebRequest puisque je sais que je peux le faire fonctionner".

Le plus grand indice quant à ce que le problème est ici est probablement le modèle «fonctionne, ne fonctionne pas, ne fonctionne pas», qu'est-ce qui cause cela? Que puis-je faire pour éviter l'IOException que je reçois? Existe-t-il un moyen d'obtenir le comportement «fonctionne toujours» que je peux voir lorsque je fais le HTTPS avec HttpWebRequest?

Il devrait y avoir quelque chose que je peux faire avec TcpClient pour qu'il agisse et réagisse comme le fait HttpWebRequest, mais je n'y suis pas encore. Des idées?

Remarque: Le serveur avec lequel je communique est configurable pour savoir sur quel port il écoute et quel protocole il attend, mais il est par ailleurs totalement non modifiable. Notez également: J'ai lu que .net 3.5 avait ce problème particulier avec SslStream avant SP1, mais j'ai SP1 et mon programme est conçu pour cibler 3.5 donc je suppose que ce n'est pas un 'connu' bug 'Je cours ici.

Répondre

3

Je ne le saurais pas, après Je passe le temps en formant la question quand je tombe sur la réponse.

est ici la documentation pertinente: jpsanders blog entry

La partie importante était la suivante:

Si la pile de l'exception comprend quelque chose de similaire à ceci: System.IO.IOException: L'authentification a échoué parce que la partie à distance a fermé le flux de transport. Il est possible que le serveur soit un serveur plus ancien ne comprend pas TLS et donc vous devez changer cela comme spécifié dans le 915599 kb à quelque chose comme ceci: ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3; Avant de faire des appels HTTPS dans votre application.

Je change mes accepté protocoles à ceci: (suppression de la possibilité de TLS)

SslProtocols protocol = SslProtocols.Ssl2 | SslProtocols.Ssl3; 

Et tout fonctionne très bien.
J'autorisais TLS, donc il essaie cela en premier, et le serveur ne le supporte pas, donc le flux est fermé. La prochaine fois qu'il utilise Ssl2 ou Ssl3 et tout va bien. Ou quelque chose comme ça. Ca marche, je suis un panda heureux.

Questions connexes