2010-06-29 4 views
2

У меня есть система связи, основанная на TcpClient, и она отлично работает, за исключением того, что она делает HTTPS для определенного IP-адреса. Затем он начинает терпеть неудачу.Как сделать HTTPS с TcpClient так же, как HttpWebRequest?

С помощью браузера или HttpWebRequest у меня нет проблем с HTTPS для этого IP-адреса.

Я создал тестовую программу, чтобы сузить проблему вплоть до своей основной сущности, вы можете посмотреть на него здесь, если вы хотите: TestViaTcp

Это тестовая программа отлично работает для базовой HTTP на тот же IP , он всегда производит успешный ответ на запрос. Я помещаю его в цикл, запускаю его с помощью нажатия клавиши, он будет продолжать работать в течение всего дня. Как только я переключаю 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, которое я получаю? Есть ли способ получить поведение «всегда работает», которое я могу видеть, когда я делаю HTTPS с помощью HttpWebRequest?

Должно быть что-то, что я могу сделать с TcpClient, чтобы заставить его действовать и реагировать так же, как HttpWebRequest, но я еще не там. Есть идеи?

Примечание. Сервер, с которым я общаюсь, настраивается относительно того, какой порт он прослушивает и какой протокол он ожидает, но в остальном полностью не поддается изменению.

Также обратите внимание: я прочитал, что .net 3.5 имел эту особую проблему с SslStream до SP1, но у меня есть SP1, а моя программа построена на 3.5, поэтому я предполагаю, что это не «известный ошибка. Я бегу сюда.

ответ

3

Разве вы не знали об этом, после Я трачу время на то, чтобы задать вопрос, когда я наткнулся на ответ.

Вот соответствующая документация: jpsanders blog entry

Важной частью была такова:

Если стек из исключения включает в себя что-то похожее на это: System.IO.IOException: Аутентификация не удалась, поскольку удаленная сторона имеет закрыл транспортный поток. Возможно, сервер является более старым сервером, который не понимает TLS и поэтому вам нужно изменить его, как указано в 915599 kb, на что-то вроде этого: ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3; Перед тем, как делать какие-либо вызовы HTTPS в вашем приложении.

Так что я меняю принятые протоколы к этому: (исключение возможности TLS)

SslProtocols protocol = SslProtocols.Ssl2 | SslProtocols.Ssl3; 

И все прекрасно работает.
Я разрешал TLS, поэтому он сначала пытается это сделать, и сервер не поддерживает его, поэтому поток закрыт. В следующий раз он использует Ssl2 или Ssl3, и все в порядке. Или что-то типа того. Это работает, я счастливая панда.