2

我有一个基于 TcpClient 的通信系统,它工作得很好,除了它对特定 IP 执行 HTTPS 时。然后它开始失败。

通过使用浏览器或 HttpWebRequest,我对该 IP 进行 HTTPS 访问没有问题。

我创建了一个测试程序来将我的问题缩小到它的基本本质,如果你愿意,可以在这里查看它:TestViaTcp

该测试程序完美地适用于相同 IP 的基本 HTTP,它总是对请求产生成功的响应。我把它放在一个循环中,用按键触发它,它会整天继续成功。一旦我切换 HTTPS,我就会得到一个重复的模式。它会起作用,然后它不会,成功后是失败,然后是成功,整天来来回回。

我一直遇到的特别失败是这个:

{"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)}

这是附加的堆栈跟踪:

   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 和浏览器都(IIRC)使用 Win32 库来处理来回通信,而 TcpClient (AFAIK)使用托管的 .net Socket 类,所以我确信它们之间存在很大差异。我确实需要用 TcpClient 来做这件事,所以不幸的是我不能只“使用 HttpWebRequest,因为我知道我可以让它工作”。

关于问题所在的最大提示可能是“有效,无效,有效,无效”模式,这是什么原因造成的?我能做些什么来避免我得到的 IOException ?当我使用 HttpWebRequest 执行 HTTPS 时,是否有某种方法可以获得“始终有效”的行为?

我应该可以对 TcpClient 做一些事情,让它像 HttpWebRequest 一样采取行动和做出反应,但我还没有做到。有任何想法吗?

注意:我正在与之通信的服务器可配置它侦听的端口和期望的协议,但在其他方面完全不可修改。

另请注意:我读过 .net 3.5 在 SP1 之前与 SslStream 有这个特殊问题,但我有 SP1,我的程序是针对 3.5 构建的,所以我假设这不是“已知错误”我我跑到这里。

4

1 回答 1

3

你不知道吗,我花时间形成问题之后,我偶然发现了答案。

以下是相关文档:jpsanders blog entry

重要的部分是:

如果来自异常的堆栈包含类似于以下内容: System.IO.IOException: Authentication failed because the remote party has closed the transport stream。服务器可能是不支持 TLS 的旧服务器,因此您需要按照 915599 kb 中的指定将其更改为如下所示: ServicePointManager.SecurityProtocol= SecurityProtocolType.Ssl3;在您在应用程序中进行任何 HTTPS 调用之前。

所以我将我接受的协议更改为:(消除 TLS 的可能性)

SslProtocols protocol = SslProtocols.Ssl2 | SslProtocols.Ssl3;

一切都很好。
我允许 TLS,所以它首先尝试,服务器不支持它,所以流被关闭。下次它使用 Ssl2 或 Ssl3 时,一切都很好。或类似的东西。它有效,我是一只快乐的熊猫。

于 2010-06-29T17:49:26.020 回答