【发布时间】:2016-03-13 05:12:55
【问题描述】:
我正在编写一个 UDP 服务器,并希望减少每个传入和传出数据包的分配数量。我想做的一件事是重新使用我分配的 Streams 来读取和写入我的数据报包。
我有这种方法,它在接收数据包时使用BinaryReader 的实例将缓冲区读取到实例对象上。
// Simplified version of the receive data method.
private void ReceiveClientData(IAsyncResult result)
{
int receivedData = socket.EndReceiveFrom(result, ref endPoint);
if (receivedData == 0)
{
this.ListenForData(socket);
return;
}
// Read the header in from the buffer first so we know what kind of message and how to route.
this.binaryReader.BaseStream.SetLength(receivedData);
this.binaryReader.BaseStream.Seek (0, SeekOrigin.Begin);
// Can't reset the MemoryStream buffer to the new packet buffer.
// How does this get consumed by the stream without allocating a new MemoryStream(buffer)?
byte[] buffer = (byte[])result.AsyncState;
// Deserialize the bytes into the header and datagram.
IClientHeader header = new ClientHeader();
header.GetMessageFromBytes(this.binaryReader);
IClientDatagram datagram = this.datagramFactory.CreateDatagramFromClientHeader(header);
datagram.GetMessageFromBytes(this.binaryReader);
this.ListenForData(socket);
}
如果 I Seek 回到流的开头,重复使用相同的 BinaryReader 和底层 MemoryStream 是否安全?在做了一些阅读之后,似乎 Socket 不会同时读取或写入数据包,这将要求我每次调用 EndReceiveFrom 都使用 Stream。听起来您确实可以同时执行每个操作,例如读取 + 写入,但不能同时执行读取或并发写入。因此,我认为我可以重复使用阅读器,但我不确定是否可以。为此,我必须给MemoryStream 一个新的缓冲区以供读取。你可以这样做还是我需要为从套接字接收到的每个新数据包创建一个新的MemoryBuffer?
我想采用同样的方法将数据包发送回客户端。为了做到这一点,我尝试将我的MemoryStream 的长度设置为 0 并回到开头。如another answer here 中所述,这似乎不会清除缓冲区。我仍然在下面的t 中看到旧的缓冲区数据。
public void SendMessage(IServerDatagram message)
{
this.binaryStream.Seek(0, SeekOrigin.Begin);
this.binaryStream.SetLength (0);
// Contains old buffer data.
var t = this.binaryStream.GetBuffer ();
message.Serialize (this.binaryWriter);
// Contains a mixture of new bytes + old bytes.
byte[] data = this.binaryStream.GetBuffer();
this.binaryWriter.Flush ();
// Send the datagram packet.
this.udpServerSocket.SendTo(data, this.connectedClients.FirstOrDefault().Key);
}
我不提前知道缓冲区需要多大,所以我不能SetLength 到我的新缓冲区的大小。有没有其他方法可以重复使用 Stream 而不必为每条消息都实例化一个新消息?如果我每秒发送数千条消息可能会导致一些内存压力,不是吗?
【问题讨论】:
-
使用 MemoryStream,如果您想保留它,您将需要重用底层字节数组。除非您指定一个“固定”长度的 MemoryStream(通过在 ctor 上传递字节数组),否则它可以重新分配它的缓冲区……所以在水中存在危险。
标签: c# sockets udp memorystream binarywriter