从没有数据时 Stream.Read() 等待的字符串创建一个空流 [英] Create an empty stream from a string on which Stream.Read() waits when no data

查看:31
本文介绍了从没有数据时 Stream.Read() 等待的字符串创建一个空流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用我从字符串创建的流替换从 TcpClient.GetStream() 获得的流.

I am trying to replace the stream i get from TcpClient.GetStream() by a stream I create from a string.

我使用以下方法创建所述流:

I am using the following method to create said Stream:

public Stream GenerateStreamFromString(string s)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(s);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

然而,这个流是通过使用 Stream.Read() 在我不想改变的库中的某处读取的.问题是我用一个空字符串创建了这个流,因为对象需要一个流来启动,通常在使用 TcpClient 流时它会在 Stream.Read() 处停止直到它可以读取内容,但不能读取我从字符串创建的流.

However this stream is read by using Stream.Read() somewhere in a library i do not WANT to change. The problem is I create this stream with an empty string because the object needs a stream to start up, normally when using the TcpClient stream it would stop at Stream.Read() until it would have things to read but not with the stream i created from my string.

所以我的问题是,如何创建一个空流,稍后我可以向其中添加字符串中的数据?

So my question, how do I create an empty stream to which i can later add data from a string?

推荐答案

在内部使用 BlockingCollection<> 作为队列,你可以这样写:

Using internally a BlockingCollection<> as a queue, you could write something like:

public class WatitingStream : Stream
{
    private BlockingCollection<byte[]> Packets = new BlockingCollection<byte[]>();

    private byte[] IncompletePacket;
    private int IncompletePacketOffset;

    public WatitingStream()
    {
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Packets.CompleteAdding();
        }

        base.Dispose(disposing);
    }

    public override bool CanRead
    {
        get { return Packets.IsCompleted; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return Packets.IsAddingCompleted; }
    }

    public override void Flush()
    {
    }

    public override long Length
    {
        get
        {
            throw new NotSupportedException();
        }
    }

    public override long Position
    {
        get
        {
            throw new NotSupportedException();
        }
        set
        {
            throw new NotSupportedException();
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        if (count == 0)
        {
            return 0;
        }

        byte[] packet;
        int packetOffset;

        if (IncompletePacket != null)
        {
            packet = IncompletePacket;
            packetOffset = IncompletePacketOffset;
        }
        else
        {
            if (Packets.IsCompleted)
            {
                return 0;
            }

            packet = Packets.Take();
            packetOffset = 0;
        }

        int read = Math.Min(packet.Length - packetOffset, count);
        Buffer.BlockCopy(packet, packetOffset, buffer, offset, read);

        packetOffset += read;

        if (packetOffset < packet.Length)
        {
            IncompletePacket = packet;
            IncompletePacketOffset = packetOffset;
        }
        else
        {
            IncompletePacket = null;
            IncompletePacketOffset = 0;
        }

        return read;
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotSupportedException();
    }

    public override void SetLength(long value)
    {
        throw new NotSupportedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        if (count == 0)
        {
            return;
        }

        byte[] packet = new byte[count];
        Buffer.BlockCopy(buffer, offset, packet, 0, count);
        Packets.Add(packet);
    }
}

您将其用作普通流.Write 不会阻塞.Read 块.

You use it as a normal stream. The Write doesn't block. The Read blocks.

必须做出一些决定:这个 Stream 是基于数据包"的.它不会Write零长度数据包,而Read将返回一个数据包的数据.Read 不会在下一个数据包上继续.如果在 Read 后数据包中还有数据,则保存该数据以供下一次 Read 使用.Dispose() 将停止 Write(因此,如果客户端"在服务器"之前执行 Dispose(),服务器将如果它尝试执行 Write,则会得到一个异常.如果服务器"首先执行 Dispose(),客户端"可以完成读取仍然存在的数据包.显然可以(容易)将这个类分成两个类(一个 Server 和一个 Client),其中 Server 保留 BlockingCollection<> 并且客户端具有对服务器"的引用.这将解决Dispose()"异常/问题(但会使代码大小加倍:-))

Some decisions had to be taken: this Stream is "packet" based. It won't Write zero-length packets, and a Read will return the data of one packet. The Read won't continue on the next packet. If there is data remaining in a packet after a Read, that data is saved for the next Read. The Dispose() will stop the Write (so if the "client" does a Dispose() before the "server", the server will get an exception if it tries to do a Write). If the "server" does the Dispose() first, the "client" can finish reading the packets still present. Clearly it is possible (easy) to split this class in two classes (one Server and one Client), where the Server keeps the BlockingCollection<> and the Client has a reference to the "server". This would solve the "Dispose()" anomaly/problem (but would double the code size :-) )

这篇关于从没有数据时 Stream.Read() 等待的字符串创建一个空流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆