c# - 如何像 HttpWebRequest 一样使用 TcpClient 执行 HTTPS?

标签 c# httpwebrequest tcpclient ioexception

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

通过使用浏览器或 HttpWebRequest,我可以毫无问题地使用 HTTPS 访问该 IP。

我创建了一个测试程序来将我的问题缩小到其基本本质,如果您愿意,您可以在这里查看它: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 一样行动和 react ,但我还没有做到这一点。有什么想法吗?

注意:我正在通信的服务器可以配置它监听的端口以及它期望的协议(protocol),但在其他方面是完全不可修改的。

另请注意:我已经读到 SP1 之前的 .net 3.5 与 SslStream 存在这个特定问题,但我已经有了 SP1 并且我的程序是针对 3.5 构建的,所以我假设这不是一个“已知错误” '我正跑到这里来。

最佳答案

你难道不知道吗,我花时间提出问题之后,就是我偶然发现答案的时候。

以下是相关文档:jpsanders blog entry

重要的部分是:

如果异常堆栈包含类似以下内容:System.IO.IOException:身份验证失败,因为远程方已关闭传输流。服务器可能是较旧的服务器,不支持 TLS,因此您需要将 915599 kb 中指定的值更改为如下所示: ServicePointManager.SecurityProtocol= SecurityProtocolType.Ssl3; 在应用程序中进行任何 HTTPS 调用之前。

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

SslProtocols protocol = SslProtocols.Ssl2 | SslProtocols.Ssl3;

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

关于c# - 如何像 HttpWebRequest 一样使用 TcpClient 执行 HTTPS?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3143010/

相关文章:

.net - HttpWebRequest.GetResponse 在 HTTP 304 上抛出 WebException

用 python 编写的类似 Javascript 的 TCP 套接字客户端?

Android TCP连接最佳实践

java - 如何在 android 中创建这个嵌套的 JSON 对象并在 c# 中对其进行解码?

中型集合中的 C# 大对象

c# - 为什么 DateTime.Now 和 StopWatch 会漂移?

c# - 使用 Httpwebrequest 发送文件

c# - 记录已处理的异常

.net - HttpWebRequest 的 Timeout 和 ReadWriteTimeout——这些对底层 TCP 连接意味着什么?

java - socket.shutdownOutput() 的目的