代码之家  ›  专栏  ›  技术社区  ›  sipsorcery

在不发送未完成的结束元素的情况下释放XmlWriter

  •  2
  • sipsorcery  · 技术社区  · 14 年前

    我用的是 XmlWriter 发送一个xmpp(jingle)流。XMPP协议在协商TLS时替换了XML流,这意味着XML的结尾如下:

    <stream>
     <features>
      ...
     </features>
    
     ...TLS gets negotiated...
    
    <stream>
     ...
    </stream>
    

    XML的格式不正确,因为有两个流开始标记。

    我要做的是扔掉 XMLX 在进行TLS协商之前,我正在使用它并创建一个全新的,它允许我更好地模块化我的代码。但是当我打电话的时候 myXmlWriter.Close() 为了确保它被释放,它将发送关闭流结束元素,这会破坏XMPP协议。

    1 回复  |  直到 14 年前
        1
  •  1
  •   Pieter van Ginkel    14 年前

    创建一个中间流,您可以使用它来断开XML编写器与基流的连接。

    这不是最优雅的解决方案,下面的代码需要工作,所以在将其投入生产之前对其进行测试,但这是关于这个想法的。

    public class DummyStream : Stream
    {
        public DummyStream(Stream baseStream)
        {
            if (baseStream == null)
                throw new ArgumentNullException("baseStream");
    
            BaseStream = baseStream;
        }
    
        public Stream BaseStream { get; private set; }
    
        public void DisconnectBaseStream()
        {
            BaseStream = null;
        }
    
        private Stream GetBaseStream()
        {
            return BaseStream ?? Stream.Null;
        }
    
        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            return GetBaseStream().BeginRead(buffer, offset, count, callback, state);
        }
    
        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
        {
            return GetBaseStream().BeginWrite(buffer, offset, count, callback, state);
        }
    
        public override bool CanRead
        {
            get { return GetBaseStream().CanRead; }
        }
    
        public override bool CanSeek
        {
            get { return GetBaseStream().CanSeek; }
        }
    
        public override bool CanTimeout
        {
            get { return GetBaseStream().CanTimeout; }
        }
    
        public override bool CanWrite
        {
            get { return GetBaseStream().CanWrite; }
        }
    
        public override void Close()
        {
            // We do not close the BaseStream because this stream
            // is just a wrapper.
    
            // GetBaseStream().Close();
        }
    
        public override ObjRef CreateObjRef(Type requestedType)
        {
            return GetBaseStream().CreateObjRef(requestedType);
        }
    
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
    
            // We do not dispose the BaseStream because this stream
            // is just a wrapper.
        }
    
        public override int EndRead(IAsyncResult asyncResult)
        {
            return GetBaseStream().EndRead(asyncResult);
        }
    
        public override void EndWrite(IAsyncResult asyncResult)
        {
            GetBaseStream().EndWrite(asyncResult);
        }
    
        public override bool Equals(object obj)
        {
            return GetBaseStream().Equals(obj);
        }
    
        public override void Flush()
        {
            GetBaseStream().Flush();
        }
    
        public override int GetHashCode()
        {
            return GetBaseStream().GetHashCode();
        }
    
        public override object InitializeLifetimeService()
        {
            return GetBaseStream().InitializeLifetimeService();
        }
    
        public override long Length
        {
            get { return GetBaseStream().Length; }
        }
    
        public override long Position
        {
            get { return GetBaseStream().Position; }
            set { GetBaseStream().Position = value; }
        }
    
        public override int Read(byte[] buffer, int offset, int count)
        {
            return GetBaseStream().Read(buffer, offset, count);
        }
    
        public override int ReadByte()
        {
            return GetBaseStream().ReadByte();
        }
    
        public override int ReadTimeout
        {
            get { return GetBaseStream().ReadTimeout; }
            set { GetBaseStream().ReadTimeout = value; }
        }
    
        public override long Seek(long offset, SeekOrigin origin)
        {
            return GetBaseStream().Seek(offset, origin);
        }
    
        public override void SetLength(long value)
        {
            GetBaseStream().SetLength(value);
        }
    
        public override string ToString()
        {
            return GetBaseStream().ToString();
        }
    
        public override void Write(byte[] buffer, int offset, int count)
        {
            GetBaseStream().Write(buffer, offset, count);
        }
    
        public override void WriteByte(byte value)
        {
            GetBaseStream().WriteByte(value);
        }
    
        public override int WriteTimeout
        {
            get { return GetBaseStream().WriteTimeout; }
            set { GetBaseStream().WriteTimeout = value; }
        }
    }
    

    该类将用作 XmlWriter 和小溪 XMLX 正在输出到。这个类只转发来自 XMLX 到基流,但一旦调用 DisconnectBaseStream ,它停止转发它们, XMLX 无法再控制基流。

    您可以这样使用这个类:

    using (var stream = /* stream used to communicate with */)
    {
        using (var wrapperStream = new DummyStream(stream))
        using (var writer = XmlWriter.Create(wrapperStream))
        {
            // Do you work here.
    
            // Now, disconnect the dummy stream so that the XML writer
            // cannot send more data.
    
            wrapperStream.DisconnectBaseStream();
    
            // End of the using block will close the XmlWriter and it
            // cannot send more data to the base stream.
        }
    
        // Perform TLS negotiation etc...
    }
    

    再一次, DummyStream 是一个起点,需要一些工作。例如,您需要确保 XMLX 不会在断开连接后拨打会崩溃的电话,因此您需要进行一些检查,例如 Write 方法是否 BaseStream null 如果是,跳过电话。