2011-11-01 31 views
7

Tôi có một ứng dụng sử dụng SslStream để gửi và nhận dữ liệu với khung có độ dài cố định của riêng nó. Các dòng được tạo ra bằng cách gói NetworkStream trở về từ TcpClient.GetStream() như vậy:Tôi có thể mong đợi mức độ an toàn của luồng nào từ System.Net.Security.SslStream?

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

Bởi vì giao thức là hoàn toàn không đồng bộ (đóng khung "thông điệp" đến vào những thời điểm tùy ý và khách hàng được phép gửi chúng vào những thời điểm tùy ý), tôi bình thường sẽ sinh ra một sợi chịu trách nhiệm chặn trên NetworkStream.Read() và nếu không đảm bảo rằng chỉ có một chuỗi gọi NetworkStream.Write(...) tại một thời điểm bất kỳ.

Phần Remarks cho NetworkStream nói:

Đọc và ghi các hoạt động có thể được thực hiện đồng thời trên một thể hiện của lớp NetworkStream mà không cần đồng bộ hóa. Miễn là có một chuỗi duy nhất cho hoạt động ghi và một chuỗi duy nhất cho hoạt động đọc, sẽ không có sự can thiệp chéo giữa đọc và viết luồng và không cần đồng bộ hóa.

Tuy nhiên, MSDN documentation "Chủ đề an toàn" để biết SslStream nói:

Bất kỳ public static (chung trong Visual Basic) thành viên thuộc loại này là chủ đề an toàn. Bất kỳ thành viên cá thể nào cũng không được đảm bảo an toàn là an toàn cho các thanh công cụ .

SslStreamNetworkStream không nằm trong hệ thống phân cấp cùng lớp, tôi đã giả định (có thể không chính xác) rằng những nhận xét cho NetworkStream không áp dụng cho SslStream.

Cách tiếp cận tốt nhất cho an toàn luồng chỉ cần quấn SslStream.BeginRead/SslStream.EndReadSslStream.BeginWrite/SslStream.EndWrite với thứ gì đó như thế này?

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(); 
    } 
} 
+0

Chi tiết nhỏ: khóa trên _stream sẽ hoạt động nhưng bạn nên tạo và sử dụng một đối tượng riêng cho mục đích này. –

+0

@HenkHolterman Chúc mừng cho lời khuyên; Tôi đã cập nhật mã. –

+0

FWIW: [SafeSslStream] (https://github.com/smarkets/IronSmarkets/blob/master/IronSmarkets/Sockets/SafeSslStream.cs) đang được đề cập là dành cho [IronSmarkets] (https://github.com/smarkets)/IronSmarkets) dự án. –

Trả lời

3

Cụm từ bạn lấy từ tài liệu MSDN là một bản tóm tắt được đặt trong tài liệu của hầu hết các lớp. Nếu tài liệu của một thành viên tuyên bố rõ ràng an toàn luồng (như NetworkStream thì) thì bạn có thể dựa vào nó.

Tuy nhiên, điều họ nêu rõ là bạn có thể thực hiện một lần đọc và viết một lần cùng một lúc, chứ không phải hai lần đọc hoặc hai lần viết. Như vậy, bạn sẽ cần phải đồng bộ hóa hoặc xếp hàng các lần đọc của bạn và viết riêng. Mã của bạn có vẻ đủ để làm điều này.

+0

Điều tôi vẫn chưa chắc chắn là các nhận xét chỉ xuất hiện trong 'NetworkStream' và' SslStream' không tự thừa hưởng từ 'NetworkStream' mà thay vào đó xuất hiện để bọc nó khi được sử dụng với' TcpClient'. –

+0

Vì SslStream của bạn sẽ bao bọc một NetworkStream, bạn sẽ nhận được sự an toàn của luồng ngầm trên các hoạt động đọc và ghi một cách độc lập. Nếu đây không phải là trường hợp, SSL sẽ là half-duplex (mà nó không phải là). Bạn có thể chỉ cần đọc và viết trong ổ khóa riêng của họ và nó sẽ được an toàn. – Polynomial

+1

Chỉ cần thêm một số độ chính xác: trong khi hầu hết SSL là full-duplex, bắt tay yêu cầu đồng bộ hóa các chỉ đọc và viết; và máy khách và máy chủ có thể yêu cầu bắt tay lại bất cứ lúc nào. Vì vậy, có thể đọc được trong một luồng và viết trong một luồng khác, không đồng bộ hóa, không phải là một hệ quả rõ ràng của luồng-an toàn của NetworkStream. May mắn thay, việc thực thi SslStream của Microsoft bao gồm các khóa nội bộ cần thiết để cho phép hoạt động hai luồng như vậy (tôi chưa kiểm tra Mono). –

Các vấn đề liên quan