从没有数据时 Stream.Read() 等待的字符串创建一个空流 [英] Create an empty stream from a string on which Stream.Read() waits when no data
问题描述
我正在尝试用我从字符串创建的流替换从 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屋!