我可以从System.Net.Security.SslStream获得什么级别的线程安全性?

时间:2011-11-01 16:52:28

标签: c# ssl thread-safety sslstream

我有一个应用程序使用SslStream来发送和接收具有自己的固定长度框架的数据。通过包装从NetworkStream返回的TcpClient.GetStream()来创建流,如下所示:

var client = new TcpClient();
client.Connect(host, port);
var sslStream = new SslStream(client.GetStream(), false, callback, null);
sslStream.AuthenticateAsClient(hostname);

因为协议是完全异步的(框架“消息”在任意时间到达并且允许客户端在任意时间发送它们),我通常会生成一个负责阻塞NetworkStream.Read()的线程,否则确保任何时候只有一个线程调用NetworkStream.Write(...)

NetworkStream的{​​{3}}部分说:

  

读取和写入操作可以同时执行   不需要NetworkStream类的实例   同步。只要有一个独特的线程   写操作和一个用于读操作的唯一线程,   读写之间不会存在交叉干扰   线程并且不需要同步。

但是,SslStream的{​​{3}}“主题安全”部分说明了:

  

此类型的任何公共静态(在Visual Basic中为Shared)成员   是线程安全的。不保证任何实例成员   线程安全。

由于SslStreamNetworkStream不在同一个类层次结构中,我假设(可能不正确)NetworkStream的评论不适用于SslStream

线程安全的最佳方法是简单地将SslStream.BeginRead / SslStream.EndReadSslStream.BeginWrite / SslStream.EndWrite包裹起来吗?

internal sealed class StateObject
{
    private readonly ManualResetEvent _done = new ManualResetEvent(false);

    public int BytesRead { get; set; }
    public ManualResetEvent Done { get { return _done; } }
}

internal sealed class SafeSslStream
{
    private readonly object _streamLock = new object();
    private readonly SslStream _stream;

    public SafeSslStream(SslStream stream)
    {
        _stream = stream;
    }

    public int Read(byte[] buffer, int offset, int count)
    {
        var state = new StateObject();
        lock (_streamLock)
        {
             _stream.BeginRead(buffer, offset, count, ReadCallback, state);
        }
        state.Done.WaitOne();
        return state.BytesRead;
    }

    public void Write(byte[] buffer, int offset, int count)
    {
        var state = new StateObject();
        lock (_streamLock)
        {
            _stream.BeginWrite(buffer, offset, count, WriteCallback, state);
        }
        state.Done.WaitOne();
    }

    private void ReadCallback(IAsyncResult ar)
    {
        var state = (StateObject)ar.AsyncState;
        lock (_streamLock)
        {
            state.BytesRead = _stream.EndRead(ar);
        }
        state.Done.Set();
    }

    private void WriteCallback(IAsyncResult ar)
    {
        var state = (StateObject)ar.AsyncState;
        lock (_streamLock)
        {
            _stream.EndWrite(ar);
        }
        state.Done.Set();
    }
}

1 个答案:

答案 0 :(得分:3)

您从MSDN文档中提取的短语是大多数类文档中的全部内容。如果成员的文档明确说明了线程的安全性(如NetworkStream那样),那么你可以依赖它。

然而,他们所说的是你可以同时执行一次读取和一次写入,而不是两次读取或两次写入。因此,您需要单独同步或排队读取和写入。您的代码看起来足以完成此任务。