-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
There's a bug in the current read loop in both SimpleAsyncServer and SimpleAsyncClient:
while (!_cancellation.Token.IsCancellationRequested)
{
var buffer = new byte[_bufferSize];
var bytesRead = await netStream.ReadAsync(buffer, 0, buffer.Length);
bool messageReceived = framer.DataReceived(buffer);
if (messageReceived)
{
if (OnMessageReceived != null)
OnMessageReceived.Invoke(this, new SACMessageReceivedEventArgs(framer.GetMessage(), framer.GetMessage().Length));
}
}Consider the following scenario:
- Message sizes are 250 bytes, server is writing a burst of messages.
- first time netStream.ReadAsync starts, it read a buffer, buffer contains 2600 bytes (hence 10 messages and some bytes from an uncompleted message)
- the framer will only extract the first message (placing it in the previousDataBuffer so the framer.getMessage() will fetch it)
- the loop will then continue, reading new buffer from netStream, passing it to the framer.
at this point, few things will happen: - The rest of the 9 messages previously read are gone
- the lengthBuffer will read some random 4 bytes, giving a bogus data size (either huge or negative) causing the framer to fail, and the entire stream to be unrecoverable.
I worked around this by adding a readMessage method, but this is just a quick patch, the better approach is to of course solve this within the framer (keeping with the current (good) architecture.
My temporary work around:
(Do note I didn't use wait/async for readSize and readMessage, since they will block anyhow, I don't see the point in that, but you can very well do so.
using (NetworkStream netStream = _tcpClient.GetStream())
{
while (!_cancellation.Token.IsCancellationRequested)
{
byte[] message = ReadMessage(netStream);
OnMessageReceived.Invoke(this, new SACMessageReceivedEventArgs(message, message.Length));
}
}
private byte[] ReadMessage(NetworkStream netStream)
{
int msgSize = ReadSize(netStream);
byte[] message = new byte[msgSize];
int read = 0;
while (read < msgSize)
{
read += netStream.Read(message, read, msgSize - read);
}
return message;
}
private int ReadSize(NetworkStream netStream)
{
byte[] sizeBuffer = new byte[sizeof(int)];
int read = 0;
while (read < sizeBuffer.Length)
read += netStream.Read(sizeBuffer, read, sizeBuffer.Length - read);
return BitConverter.ToInt32(sizeBuffer, 0);
}