How to do HTTPS with TcpClient just like HttpWebRequest does?
我有一个基于TcpClient的通信系统,除了它对特定IP进行HTTPS之外,它的工作原理非常好。然后它开始失败。
通过使用浏览器或HttpWebRequest,对该IP执行HTTPS不会出现问题。
我创建了一个测试程序,将问题缩小到其基本本质,如果需要,可以在这里查看:TestViaTcp
该测试程序完美地适用于同一IP的基本HTTP,它始终能够成功响应请求。我将其循环放置,通过按键触发它,它将持续整天成功。切换HTTPS后,我将获得一个重复模式。成功会成功,然后失败,然后整天来回成功。
我一直遇到的特定故障是:
1 2 3 4 5 6 7 8 | {"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)} |
这是附加的堆栈跟踪:
1 2 3 4 5 6 7 8 | 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构建的,所以我假设这不是"已知错误",我碰到这里。
在我花时间整理问题之后,您会不知道该怎么回答。
以下是相关文档:jpsanders博客条目
重要的部分是:
如果异常中的堆栈包含与此类似的内容:System.IO.IOException:身份验证失败,因为远程方已关闭传输流。该服务器可能是较旧的服务器,可能无法理解TLS,因此您需要按照915599 kb中的指定将其更改为以下内容:ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;在应用程序中进行任何HTTPS调用之前。
因此,我将接受的协议更改为此:(消除了TLS的可能性)
1 | SslProtocols protocol = SslProtocols.Ssl2 | SslProtocols.Ssl3; |
一切都很好。
我允许使用TLS,因此它首先尝试使用该方法,而服务器不支持它,因此关闭了流。下次使用Ssl2或Ssl3时,一切正常。或类似的东西。它有效,我是快乐的熊猫。