Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# System.Net.Security.SslStream的线程安全级别是什么?_C#_Ssl_Thread Safety_Sslstream - Fatal编程技术网

C# System.Net.Security.SslStream的线程安全级别是什么?

C# System.Net.Security.SslStream的线程安全级别是什么?,c#,ssl,thread-safety,sslstream,C#,Ssl,Thread Safety,Sslstream,我有一个应用程序,它使用SslStream以自己的固定长度帧发送和接收数据。流是通过包装从TcpClient.GetStream()返回的NetworkStream创建的,如下所示: var client = new TcpClient(); client.Connect(host, port); var sslStream = new SslStream(client.GetStream(), false, callback, null); sslStream.AuthenticateAsCl

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

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类的实例,而不需要 同步。只要有一个唯一的线程 写操作和读操作的唯一线程, 读写之间不会有交叉干扰 线程,无需同步

但是,
SslStream
的“线程安全”部分指出:

此类型的任何公共静态(在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();
    }
}

从MSDN文档中提取的短语是大多数类文档中的一个包罗万象的短语。如果一个成员的文档明确声明了线程安全性(就像
NetworkStream
那样),那么您可以依赖它


但是,他们说的是,您可以同时执行一次读取和一次写入,而不是两次读取或两次写入。因此,您需要分别对读写操作进行同步或排队。您的代码看起来足以做到这一点。

我仍然不确定的是,备注仅出现在
NetworkStream
中,
SslStream
本身并不是从
NetworkStream
继承的,而是在与
TcpClient
一起使用时似乎会将其包装。因为您的ssstream将包装一个NetworkStream,您可以独立地在读写操作上获得隐式线程安全性。如果不是这样,SSL将是半双工的(事实并非如此)。您只需将读写封装在自己的锁中,这将是安全的。只需增加一些精度:虽然大多数SSL是全双工的,但握手需要同步读写方向;客户端和服务器可以随时请求重新握手。因此,能够在一个线程中进行读取,在另一个线程中进行写入,而不需要同步,这并不是NetworkStream线程安全的明显后果。幸运的是,微软对SslStream的实现包括了允许这种双线程操作所必需的内部锁(尽管我没有检查Mono)。@Thomasbornin Good shout。我会很快检查Mono,看看他们是否反映了这种安全性;如果不是的话,会导致一些有趣的错误!微小细节:锁定流将起作用,但建议为此创建并使用单独的对象。@HenkHolterman为建议喝彩;我更新了代码。FWIW:问题是这个项目。