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:问题是这个项目。