我也遇到了一个问题,SslStream在超时后返回五个垃圾数据字节,我单独想出了一个解决方案,与OP的第三次更新类似。
我创建了一个包装类,将Tcp NetworkStream对象包装起来传递给SslStream构造函数。这个包装类将所有调用都传递到底层的NetworkStream,除了Read()方法,它包含了额外的try...catch以抑制Timeout异常并返回0字节。
在这种情况下,SslStream正常工作,包括在套接字关闭时引发适当的IOException。请注意,我们的Stream从Read()返回0与TcpClient或Socket从Read()返回0是不同的(通常表示套接字断开连接)。
class SocketTimeoutSuppressedStream : Stream
{
NetworkStream mStream;
public SocketTimeoutSuppressedStream(NetworkStream pStream)
{
mStream = pStream;
}
public override int Read(byte[] buffer, int offset, int count)
{
try
{
return mStream.Read(buffer, offset, count);
}
catch (IOException lException)
{
SocketException lInnerException = lException.InnerException as SocketException;
if (lInnerException != null && lInnerException.SocketErrorCode == SocketError.TimedOut)
{
return 0;
}
throw;
}
}
public override bool CanRead => mStream.CanRead;
public override bool CanSeek => mStream.CanSeek;
public override bool CanTimeout => mStream.CanTimeout;
public override bool CanWrite => mStream.CanWrite;
public virtual bool DataAvailable => mStream.DataAvailable;
public override long Length => mStream.Length;
public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) => mStream.BeginRead(buffer, offset, size, callback, state);
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state) => mStream.BeginWrite(buffer, offset, size, callback, state);
public void Close(int timeout) => mStream.Close(timeout);
public override int EndRead(IAsyncResult asyncResult) => mStream.EndRead(asyncResult);
public override void EndWrite(IAsyncResult asyncResult) => mStream.EndWrite(asyncResult);
public override void Flush() => mStream.Flush();
public override Task FlushAsync(CancellationToken cancellationToken) => mStream.FlushAsync(cancellationToken);
public override long Seek(long offset, SeekOrigin origin) => mStream.Seek(offset, origin);
public override void SetLength(long value) => mStream.SetLength(value);
public override void Write(byte[] buffer, int offset, int count) => mStream.Write(buffer, offset, count);
public override long Position
{
get { return mStream.Position; }
set { mStream.Position = value; }
}
public override int ReadTimeout
{
get { return mStream.ReadTimeout; }
set { mStream.ReadTimeout = value; }
}
public override int WriteTimeout
{
get { return mStream.WriteTimeout; }
set { mStream.WriteTimeout = value; }
}
}
可以通过在将TcpClient NetworkStream对象传递给SslStream之前对其进行包装来使用,如下所示:
NetworkStream lTcpStream = lTcpClient.GetStream()
SocketTimeoutSuppressedStream lSuppressedStream = new SocketTimeoutSuppressedStream(lTcpStream)
using (lSslStream = new SslStream(lSuppressedStream, true, ServerCertificateValidation, SelectLocalCertificate, EncryptionPolicy.RequireEncryption))
问题在于SslStream在底层流出现任何异常,甚至是一个无害的超时,都会破坏其内部状态。奇怪的是,下一个read()返回的五个(左右)字节实际上是来自线路的TLS加密负载数据的开头。
希望这能有所帮助。