Какой уровень безопасности потока я могу ожидать от System.Net.Security.SslStream? - PullRequest
7 голосов
/ 01 ноября 2011

У меня есть приложение, которое использует 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 говорится:

Операции чтения и записи могут выполняться одновременно для экземпляра класса NetworkStream без необходимости синхронизации.Пока существует один уникальный поток для операций записи и один уникальный поток для операций чтения, не будет перекрестных помех между потоками чтения и записи и синхронизация не требуется.

Однако, документация MSDN В разделе «Потоковая безопасность» для SslStream говорится:

Любые открытые статические (Shared в Visual Basic) члены этого типа являются поточно-ориентированными.Ни один член экземпляра не гарантированно является потокобезопасным.

Поскольку SslStream и NetworkStream не находятся в одной иерархии классов, я предположил (возможно, неправильно), что замечания для NetworkStream не относится к SslStream.

Является ли наилучшим подходом для обеспечения безопасности потоков просто обернуть SslStream.BeginRead / SslStream.EndRead и SslStream.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 Ответ

3 голосов
/ 01 ноября 2011

Фраза, которую вы извлекли из документов MSDN, является всеобъемлющей и содержится в документации большинства классов. Если в документации участника явно говорится о безопасности потоков (как это делает NetworkStream), вы можете на нее положиться.

Однако они заявляют, что вы можете выполнять одно чтение и одну запись одновременно, а не две операции чтения или две записи. Таким образом, вам нужно будет синхронизировать или поставить в очередь ваши чтения и записи отдельно. Ваш код выглядит достаточно для этого.

...