私はSslStream
を使って独自の固定長フレーミングでデータを送受信するアプリケーションを持っています。私は、System.Net.Security.SslStreamからどのレベルのスレッドセーフが期待できますか?
var client = new TcpClient();
client.Connect(host, port);
var sslStream = new SslStream(client.GetStream(), false, callback, null);
sslStream.AuthenticateAsClient(hostname);
をプロトコルが完全に非同期であるため(フレーム「メッセージ」、任意の時間に到着し、クライアントが任意のタイミングでそれらを送信することが許可されている):ストリームがNetworkStream
がそうのようTcpClient.GetStream()
から返されたラップによって作成されました通常はNetworkStream.Read()
でブロックするスレッドを生成し、それ以外の場合はいつでもNetworkStream.Write(...)
を呼び出すスレッドが1つしかないことを確認します。
NetworkStream
ためRemarksセクションは言う:
読み取りおよび書き込み操作が 同期を必要とせずにNetworkStreamクラスの インスタンス上で同時に行うことができます。 書き込み操作用に1つのユニークスレッドがあり、読み取り操作に1つのユニークスレッドがある限り、 スレッドの読み取りと書き込みの間に相互干渉はなく、同期は不要です。
しかし、SslStream
ためMSDN documentation "スレッドセーフ" セクションは言う:
(Visual BasicではShared)すべてのパブリックstaticこのタイプ のメンバーは、スレッドセーフです。すべてのインスタンスメンバは、 スレッドセーフであることは保証されていません。
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();
}
}
細かいディテール:_streamでロックすることはできますが、この目的のために別のオブジェクトを作成して使用することをお勧めします。 –
@HenkHolterman助言のための乾杯;私はコードを更新しました。 –
FWIW:[SafeSslStream](https://github.com/smarkets/IronSmarkets/blob/master/IronSmarkets/Sockets/SafeSslStream.cs)は、[IronSmarkets](https://github.com/smarkets)用です。/IronSmarkets)プロジェクト。 –