数据加密在通讯环应用是必不可少的,TLS加密通讯则是现有通讯的加密标准,可以使用.NETCore带的SslStream来集成这一功能;但SslStream的读写操作功能有限,在组件设计中不仅让SslStream使用PipeStream,同时也可以让SslStream直接转换成PipeStream进行更简便的数据流操作。

扩展

为了更好地让SslStream和PipeStream相结合操作,所以对SslStream扩展出一个新的类SslStreamX,通过它可以更好的在流数据处理隐藏SslStream和PipeStream之间的操作处理。

  1. class SslStreamX : SslStream
  2. {
  3. //构建SslStreamX,并指写来源的缓冲池,编码,存储字序和基础的数据流
  4. public SslStreamX(IBufferPool pool, Encoding encoding, bool littleEndian, Stream innerStream, bool leaveInnerStreamOpen)
  5. : base(innerStream, leaveInnerStreamOpen)
  6. {
  7. BufferPool = pool;
  8. Encoding = encoding;
  9. LittleEndian = littleEndian;
  10. mPipeStream = new PipeStream(BufferPool, LittleEndian, Encoding);
  11. mPipeStream.FlashCompleted = OnWriterFlash;
  12. mPipeStream.InnerStream = this;
  13. }
  14. //构建SslStreamX,并指写来源的缓冲池,编码,存储字序,基础的数据流和验证回调方法
  15. public SslStreamX(
  16. IBufferPool pool, Encoding encoding, bool littleEndian, Stream innerStream, RemoteCertificateValidationCallback callback)
  17. : base(innerStream, false, callback, null)
  18. {
  19. BufferPool = pool;
  20. Encoding = encoding;
  21. LittleEndian = littleEndian;
  22. mPipeStream = new PipeStream(BufferPool, LittleEndian, Encoding);
  23. mPipeStream.FlashCompleted = OnWriterFlash;
  24. mPipeStream.InnerStream = this;
  25. }
  26. public IBufferPool BufferPool { get; set; }
  27. public Encoding Encoding { get; set; }
  28. public bool LittleEndian { get; set; }
  29. private PipeStream mPipeStream;
  30. //提交数据到SslStream
  31. private void OnWriterFlash(Buffers.IBuffer data)
  32. {
  33. StreamHelper.WriteBuffer(this, data);
  34. }
  35. //提交数据
  36. public override void Flush()
  37. {
  38. if (mPipeStream != null)
  39. mPipeStream.Flush();
  40. base.Flush();
  41. }
  42. //获取当前SslStream对应的PipeStream
  43. public PipeStream GetPipeStream()
  44. {
  45. return mPipeStream;
  46. }
  47. public Exception SyncDataError { get; set; }
  48. public bool AsyncDataStatus { get; set; }
  49. //同步接收的数据到PipeStream中
  50. public async void SyncData(Action receive)
  51. {
  52. while (true)
  53. {
  54. var dest = GetPipeStream();
  55. IBuffer buffer = null;
  56. try
  57. {
  58. buffer = BufferPoolGroup.DefaultGroup.Next().Pop();
  59. int rlen = await ReadAsync(buffer.Data, 0, buffer.Size);
  60. if (rlen > 0)
  61. {
  62. buffer.SetLength(rlen);
  63. dest.Import(buffer);
  64. }
  65. else
  66. {
  67. buffer.Free();
  68. SyncDataError = new BXException("ssl receive null data!");
  69. break;
  70. }
  71. }
  72. catch (Exception e_)
  73. {
  74. SyncDataError = e_;
  75. buffer?.Free();
  76. break;
  77. }
  78. finally
  79. {
  80. receive?.Invoke();
  81. }
  82. }
  83. }
  84. //释放流
  85. protected override void Dispose(bool disposing)
  86. {
  87. base.Dispose(disposing);
  88. if (mPipeStream != null)
  89. {
  90. mPipeStream.Dispose();
  91. mPipeStream = null;
  92. }
  93. }
  94. }

(https://github.com/IKende/BeetleX/blob/master/src/BeetleX/Buffers/SslStramX.cs)
由于实现机制上的差异,SslStreamX的读写数据流是不建议直接调用SslStream的Read/Write方法进行;而是通过GetPipeStream获取内部的PipeStream进行一个写入操作;实际上PipeStream的写入并没有直接提交给SslStreamX,而是当SslStreamX提交的时候再把写入的数据流一次过提交给SslStream。

数据同步

SslStreamX提供了一个同步数据的方法SyncData,主要是通过异步读取基础数据流,如果有数据则读取的数据导入到内部的PipeStream对象并回调; 接下来看一下如何在Socket中使用SslStreamX.

  1. public void CreateSSL(AsyncCallback asyncCallback, ListenHandler listen, IServer server)
  2. {
  3. try
  4. {
  5. if (server.EnableLog(EventArgs.LogType.Info))
  6. server.Log(EventArgs.LogType.Info, null, $"{RemoteEndPoint} create ssl stream");
  7. mBaseNetStream.SSL = true;
  8. mSslStream = new SslStreamX(this.SendBufferPool, server.Options.Encoding,
  9. server.Options.LittleEndian, mBaseNetStream, false);
  10. mSslStream.BeginAuthenticateAsServer(listen.Certificate, false, listen.SslProtocols,true, new AsyncCallback(asyncCallback),
  11. new Tuple<TcpSession, SslStream>(this, this.mSslStream));
  12. }
  13. catch (Exception e_)
  14. {
  15. if (server.EnableLog(EventArgs.LogType.Warring))
  16. server.Log(EventArgs.LogType.Warring, this, $"{this.RemoteEndPoint} create session ssl error {e_.Message}@{e_.StackTrace}");
  17. this.Dispose();
  18. }
  19. }

https://github.com/IKende/BeetleX/blob/master/src/BeetleX/Buffers/SslStramX.cs
以上是组件针对SslStreamX的一个集成代码。