I'm working on Serialport. I'm facing a new problem that once I receive data my data are incomplete. How can I check if my data are complete then process them, and if not, don't process them?
Here are my data receive and my send function:
private void Send(byte[] cmd)
{
bResponse = new byte[0];
Write(cmd);
}
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int iCount = comPort.BytesToRead;
byte[] bBuffer = new byte[iCount];
comPort.Read(bBuffer, 0, iCount)
if (bBuffer.Length == 1 && bBuffer[0] == ACK)
Write(new byte[] { ENQ });
else if (bBuffer.Length == 1 && bBuffer[0] == NAK)
{
Debug.WriteLine("Incomplete Message detected!");
}
else
{
bResponse = bResponse.Concat(bBuffer).ToArray();
rResponse = Decode(bResponse);
Write(new byte[] { ACK });
}
}
I know my data are received in a few packages and I need to wait until the response is complete, but I don't know based on the code above. How should I check whether the data are complete to determine whether to wait? (P.S: The size of the received response varies.)
There is no built-in concept of completeness or packet size.
You'll have to append to a buffer until you see some recognizable end-of-packet pattern that you (or someone else) defined as part of the protocol specification. - And then probably time out after a while if you haven't seen what you are looking for.
Example of old project, notice the firstindex, lastindex, you put in a character to know the length, the start/end character is predefined and can be any character you choose, just be sure not to take any common characters
This is for tcp/ip, but same principle can be used for serialport
public void ReceiveMessage(IAsyncResult ar)
{
int bytesRead;
try
{
lock (client1.GetStream())
{
bytesRead = client1.GetStream().EndRead(ar);
}
string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
received = messageReceived;
int firstindex = received.IndexOf((char)2);
int lastindex = received.IndexOf((char)3);
if (firstindex > 0 && lastindex > 0)
{
string first = received.Substring(firstindex, 1);
string last = received.Substring(lastindex, 1);
}
lock (client1.GetStream())
{
client1.GetStream().BeginRead(data, 0, System.Convert.ToInt32(client1.ReceiveBufferSize), ReceiveMessage, null);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I have some code for you.
First, you implement the DataReceived Event (as you have done already). This event is only called when there is data to process. While I would not call it interrupt-based (as in "realtime capable") is is definitely not polling. Which is good.
Second: When the event is called you may have only one byte, but there may be more bytes. To capture each packet you need to implement an custom buffer.
Third: After you append one byte to your buffer, you check whether the buffer contains a valid packet. If so, process it. If not: Append another one. If no bytes are left, wait for the event to be called again.
In code it looks like this:
const BUFFERLENGTH = 17; // Bytes
byte[] buffer = new byte[BUFFERLENGTH];
private void COM_Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
while (port.BytesToRead > 0)
{
var data = (byte)port.ReadByte();
Read(data);
}
}
private void Read(byte value)
{
// Append Byte to buffer
System.Buffer.BlockCopy(buffer, 1, buffer, 0, BUFFERLENGTH- 1);
buffer[BUFFERLENGTH - 1] = value;
// Check for valid Packet
if (IsValidPacket(buffer))
{
// Yeah! Gotcha :-)
// Now copy your Packet from the Buffer to your struct/whatever
}
}
private bool IsValidPacket(byte[] buffer)
{
// Todo: Check whether buffer contains a valid Packet.
// Some think like:
// return buffer != null && buffer[0] == 0xF4 && buffer[2] == buffer.length
throw new NotImplementedException();
}
Note that I did not "append the byte to the buffer". I discarded the first byte, shifted every byte by one position and inserted the new byte at the end. If a valid Packet was found I could just copy it in one block into a struct. So the buffer size is always constant and exactly as long as one packet.
This may not be the fastest code out there (because it's reading each byte separately) but it works well for me :-)
Oh, and remember to use Begininvoke() if you want to display that stuff in your GUI.
Related
My app is built on C# synchronous sockets, and I am trying to replace them with asynchronous ones, in order to improve efficiency (if possible). So far, I have replaced on the server the Send() and Accept() with the asynchronous ones (based on the MSDN documents), but I have some issues to implement the Receive().
Original (synchronous):
Socket _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
bool _flag = true;
CheckFun()
{
while (_flag)
{
Thread.Sleep(10); // every ~10ms check
byte[] _buffer;
if (_socket.Available != 0)
{
_buffer = new byte[1]; // just check 1st byte
_socket.Receive(_buffer, 1, SocketFlags.None);
if (_buffer[0] == 1)
{
ReceiveFun();
}
}
}
}
ReceiveFun()
{
int hdrSize = 12;
byte[] buffer = new byte[hdrSize];
_socket.Receive(buffer, hdrSize, SocketFlags.None);
int _dataLength = buffer[0]; // the 1st byte has already been removed before calling the ReceiveFun()
buffer = new byte[_dataLength];
int _bytesRead = 0;
while (_bytesRead != _dataLength)
{
while (_socket.Available == 0)
{
if (!_socket.Connected)
return 0;
}
_bytesRead += _socket.Receive(buffer, _bytesRead, _dataLength - _bytesRead, SocketFlags.None);
}
//read bytes blah blah...
}
My question is how to turn this operation into an asynchronous one and concatenate the bytes received until I receive all information? And then again wait for the next one?
EDIT
Async
public class State
{
public int nToReadBytes = 0;
public int nBytesRead = 0;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize]; // Receive buffer.
}
List<byte> lReceivedBytes = new List<byte>();
int hdrSize = 12;
public void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
var state = ar.AsyncState as State;
// Read data from the client socket.
int availableBytes = oSocket.EndReceive(ar);
if (availableBytes > 0)
{
if (lReceivedBytes.Count == 0)
{
if (state.buffer[0] == 1)
{
// the first field of the header has been successfully decoded
if (availableBytes > 1)
{
state.nToReadBytes = BitConverter.ToInt32(state.buffer, 1) + hdrSize;
int _bytesCopy = Math.Min(state.nToReadBytes, state.buffer.Length); //in case that the data is less than the State.BufferSize (unlikely)
state.nBytesRead += _bytesCopy;
lReceivedBytes.AddRange(state.buffer);
}
}
else if (state.buffer[0] == 2)
{
// the first field of the header has been successfully decoded but do nothing!
_socket.BeginReceive(state.buffer, 0, State.BufferSize, 0, new AsyncCallback(ReadCallback), state);
return;
}
else
throw new InvalidDataException("Invalid hdr field [1-2]: " + state.buffer[0]);
}
else
{
state.nBytesRead += state.buffer.Length;
lReceivedBytes.AddRange(state.buffer);
}
if (lReceivedBytes.Count == state.nToReadBytes)
{
//read all information and clear list and States in the end (?)
// ...
lReceivedBytes.Clear();
state.nToReadBytes = 0;
state.nBytesRead = 0;
_socket.BeginReceive(state.buffer, 0, State.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
else
{
//int _newSize = Math.Min(state.nToReadBytes - state.nBytesRead, State.BufferSize); // for restriction (?)
int _newSize = state.nToReadBytes - state.nBytesRead; // for now don't check
_socket.BeginReceive(state.buffer, 0, _newSize, 0, new AsyncCallback(ReadCallback), state); //shall I increase the size (it could be between 90 kB - 170kB, until all info is received)
}
}
else
_socket.BeginReceive(state.buffer, 0, State.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
The Socket class has two main asynchronous paradigms: the original callback-based Asynchronous Programming Model (APM) and the only-slightly-newed Event-based Asynchronous Pattern (EAP). Both of these can be somewhat unwieldy to implement as compared to the synchronous appproach, as they require you to adjust your thinking to connection state instead of just local method logic, breaking up what would be a single method into parts dealing with the initiation and completion of the operation.
Fortunately, the newer Task Parallel Library model leverages async and await to allow asynchronous code to be written in almost identical fashion to the equivalent synchronous version. For the Socket class, to take advantage of this, you need to wrap its asynchronous API in a TPL-compatible way. .NET does provide a general-purpose way to take existing APM APIs and wrap them in tasks (see https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/tpl-and-traditional-async-programming), but IMHO it is simpler to take advantage of the NetworkStream class, which wraps a socket in a Stream object.
Since Stream already has received the "TPL love", i.e. has ReceiveAsync() and similar methods to allow TPL-based operations, I find this somewhat easier than dealing with the wrapper methods designed to map APM to TPL.
In your code, that would wind up looking something like this:
// Somewhere appropriate -- your code example isn't specific or complete enough
// to offer anything more detailed than this
NetworkStream _stream = new NetworkStream(_socket);
async Task ReceiveFun()
{
int _bytesRead = 0, hdrSize = 12;
byte[] buffer = new byte[hdrSize];
while (_bytesRead < hdrSize)
{
int bytesRead = await _stream.ReadAsync(buffer, _bytesRead, hdrSize - _bytesRead);
if (bytesRead == 0) throw new InvalidDataException("unexpected end-of-stream");
_bytesRead += bytesRead;
}
int _dataLength = buffer[0]; // the 1st byte has already been removed before calling the ReceiveFun()
buffer = new byte[_dataLength];
_bytesRead = 0;
while (_bytesRead < _dataLength)
{
int bytesRead = await _stream.ReadAsync(buffer, _bytesRead, _dataLength - _bytesRead);
if (bytesRead == 0) throw new InvalidDataException("unexpected end-of-stream");
_bytesRead += bytesRead;
}
//read bytes blah blah...
}
Note that your original synchronous code had a bug: you were not using the returned byte count when reading the header, and so had no way to know if the full header was actually being returned in a single call or not. You must always look at the count of bytes read; this can always be as few as 1 when data is available, and of course will be 0 when the end of stream is reached (i.e. the remote endpoint uses the shutdown operation).
Your code also did not check for end-of-stream correctly. Just look at the bytes returned when you try to read from the socket. I've fixed that in the above as well.
I'm attempting to port code from DotNetty to System.IO.Pipelines. In DotNetty I'm leveraging the LengthFieldBasedFrameDecoder to decode a TCP message where the first two bytes represent an integer indicating the length of the entire message.
All the demos I've seen rely on string based EOL indicators. i feel this should be easy but it's escaping me how to grab the first two bytes, and then X amount of bytes, as indicated by the length prefix.
Below is an example taken from David Fowler's TcpEcho server. How can I rewrite this to parse the message if the first two bytes indicated the message size rather than an EOL character indicating the end of messsage?
private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
{
while (true)
{
ReadResult result = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
SequencePosition? position = null;
do
{
// Find the EOL
position = buffer.PositionOf((byte)'\n');
if (position != null)
{
var line = buffer.Slice(0, position.Value);
ProcessLine(socket, line);
// This is equivalent to position + 1
var next = buffer.GetPosition(1, position.Value);
// Skip what we've already processed including \n
buffer = buffer.Slice(next);
}
}
while (position != null);
// We sliced the buffer until no more data could be processed
// Tell the PipeReader how much we consumed and how much we left to process
reader.AdvanceTo(buffer.Start, buffer.End);
if (result.IsCompleted)
{
break;
}
}
reader.Complete();
}
This is what I ended up with:
private const int lengthPrefixSize = 2; // number of bytes in the length prefix
private static ushort ParseLengthPrefix(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer);
private static ushort ParseLengthPrefix(in ReadOnlySequence<byte> buffer)
{
if (buffer.First.Length >= lengthPrefixSize)
return ParseLengthPrefix(buffer.First.Span.Slice(0, lengthPrefixSize));
Span<byte> lengthPrefixBytes = stackalloc byte[lengthPrefixSize];
buffer.Slice(0, lengthPrefixSize).CopyTo(lengthPrefixBytes);
return ParseLengthPrefix(lengthPrefixBytes);
}
private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
{
ushort? lengthPrefix = null;
while (true)
{
ReadResult result = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
while (true)
{
if (lengthPrefix == null)
{
// If we don't have enough for the length prefix, then wait for more data.
if (buffer.Length < lengthPrefixSize)
break;
// Read and parse the length prefix
lengthPrefix = ParseLengthPrefix(buffer);
buffer = buffer.Slice(lengthPrefixSize);
}
// If we haven't read the entire packet yet, then wait.
if (buffer.Length < lengthPrefix.Value)
break;
// Read the data packet
var line = buffer.Slice(0, lengthPrefix.Value);
ProcessLine(socket, line);
buffer = buffer.Slice(lengthPrefix.Value);
lengthPrefix = null;
}
// We sliced the buffer until no more data could be processed
// Tell the PipeReader how much we consumed and how much we left to process
reader.AdvanceTo(buffer.Start, buffer.End);
if (result.IsCompleted)
{
break;
}
}
reader.Complete();
}
This solution does have a length prefix buffer, but it's only used if the length prefix is split across spans. There is a SequenceReader<T> coming that I think can make this totally copy-less, though in the case of length prefixes (very few bytes and no buffer allocations), the difference would probably be minimal.
I'm writing an interface for talking to a piece of test equipment. The equipment talks over a serial port and responds with a known number of bytes to each command I send it.
My current structure is:
Send command
Read number of specified bytes back
Proceed with application
However, when I used SerialPort.Read(byte[], int32, int32), the function is not blocking. So, for example, if I call MySerialPort.Read(byteBuffer, 0, bytesExpected);, the function returns with less than the specified number of bytesExpected. Here is my code:
public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
MySerialPort.ReadTimeout = timeOut;
int bytesRead = MySerialPort.Read(responseBytes, 0, bytesExpected);
return bytesRead == bytesExpected;
}
And I call this method like this:
byte[] responseBytes = new byte[13];
if (Connection.ReadData(responseBytes, 13, 5000))
ProduceError();
My problem is that I can't ever seem to get it to read the full 13 bytes like I am telling it. If I put a Thread.Sleep(1000) right before my SerialPort.Read(...) everything works fine.
How can I force the Read method to block until either the timeOut is exceeded or the specified number of bytes are read?
That is expected; most IO APIs allow you to specify the upper bound only - they are simply required to return at-least-one byte, unless it is an EOF in which case they can return a non-positive value. To compensate, you loop:
public bool ReadData(byte[] responseBytes, int bytesExpected, int timeOut)
{
MySerialPort.ReadTimeout = timeOut;
int offset = 0, bytesRead;
while(bytesExpected > 0 &&
(bytesRead = MySerialPort.Read(responseBytes, offset, bytesExpected)) > 0)
{
offset += bytesRead;
bytesExpected -= bytesRead;
}
return bytesExpected == 0;
}
The only problem is you might need to reduce the timeout per iteration, by using a Stopwatch or similar to see how much time has passed.
Note that I also removed the ref on responseBytes - you don't need that (you don't re-assign that value).
Try changing the timeout to InfiniteTimeout.
SerialPort.Read is expected to throw a TimeoutException in case no bytes are available before SerialPort.ReadTimeout.
So this method reads exactly the desired number or bytes, or throws an exception:
public byte[] ReadBytes(int byteCount) {
try
{
int totBytesRead = 0;
byte[] rxBytes = new byte[byteCount];
while (totBytesRead < byteCount) {
int bytesRead = comPort.Read(rxBytes, totBytesRead, byteCount - totBytesRead);
totBytesRead += bytesRead;
}
return rxBytes;
}
catch (Exception ex){
throw new MySerialComPortException("SerialComPort.ReadBytes error", ex);
}
}
I have a form in which I am able to receive data and show it in a richtextbox, but what I need is to read the data that is coming continuously from serial port and decode accordingly.
For ex: I am receiving data in bytes in the format as 36 0 0 0 1 0 0...., 36 is used to indicate start of frame n rest are the data through which an event will be fired.
My code:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
Bytenumber = serialPort1.BytesToRead;
// read one byte from buffer
ByteToRead = serialPort1.ReadByte();
this.Invoke(new EventHandler(DoUpdate));
}
Above code is used to receive data and fire an event. The code for the event is as follows:
int w=0;
public void DoUpdate(object sender, System.EventArgs e)
{
byte[] t = new byte[Bytenumber];
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead);
}
w++;
// richTextBox1.Text += ByteToRead;
if (ByteToRead == 36)
{
for (int r = 0; r <= 73; r++)
{
if (ByteToRead == 0x01)
{
timer1.Start();
w++;
}
}
}
}
In the data received event handler I am looking for 36 (i.e., start of frame) once I get that I am looking for 1s from the buffer. The problem is when I get 36 (i.e., start of frame) the same data is retained in the if loop and tries to compare with 1 which will not be true # any case. All I need is to read the next bytes of data coming from the buffer once I get 36.
I can spot a few problems. A little code-review:
Bytenumber = serialPort1.BytesToRead;
ByteNumber is the Bytes-to-Read at this moment. It is not thread-safe to keep this in a member field.
ByteToRead = serialPort1.ReadByte();
This only reads 1 Byte. And then, on another thread:
byte[] t = new byte[Bytenumber]; // ByteNumber may have changed already
for(int g=0; g<Bytenumber;g++)
{
t[g] = Convert.ToByte(ByteToRead); // store the _same_ byte in all elements
}
What you should do (not complete code):
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// get number off bytes in buffer
int n = serialPort1.BytesToRead;
byte[] buffer = new byte[n];
// read one byte from buffer
int bytesToProcess = serialPort1.Read(buffer, 0, n);
this.Invoke(UpdateMethod, buffer, bytesToProcess);
}
But do search the internet for working code. I just made this up.
After enough playing with asynchronous socket programming I noticed that the server was receiving chunked payloads (ie: more than one complete payload sitting in the same buffer). So I came up with the following:
if (bytes_to_read > 0)
{
while (bytes_to_read > 0)
// Get payload size as int.
// Get payload in byte format.
// Do something with payload.
// Decrease the amount of bytes to read.
}
// Wait for more data.
}
And then I noticed packet fragmentation (ie: what I thought were complete payloads chunked together wasn't always so) which changed the previous code to something like:
if (bytes_to_read > 0)
{
while (bytes_to_read > 0)
{
// Get payload size as int.
// Check if the payload size is less than or equal to the amount of bytes left to read.
if (payload_size <= bytes_to_read)
{
// Get payload in byte format.
// Do something with payload.
// Decrease the amount of bytes to read.
}
else
{
// We received a fragmented payload.
break;
}
}
if (bytes_to_read == 0)
{
// Wait for more data.
}
else if (bytes_to_read > 0)
{
// Wait for more data where we left off. ***
}
else
{
// Something awful happened.
}
}
*** I don't even know how to go about this and would like to see code for it. I had an idea that it involved copying the in-completed payload to the beginning of the buffer and then picking up from there.
The pseudo code I included is based on the Begin* End* method I am using (I'm aware that I should be using the *Async set of methods found here -> http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx <- but I think my overall question still applies).
I am seeking the answers to 2 questions--namely:
Is this approach correct or am I
missing something?
What does a working example of
dealing with packet fragmentation in
C# look like?
EDIT: I'm using raw sockets.
Thanks in advance for all your help.
EDIT: John Saunders and Greg Hewgill have brought up the point of treating data as a stream but that does not provide me with a concrete example of how to deal with the last chunked payload sometimes being fragmented.
EDIT: I have read Jon Skeet's answer here which is basically along the same lines as the other answers I have seen but it doesn't help me much as I already get what I have to do but not how to do it.
EDIT: To elaborate on what I mean by fragmentation, consider the following the receive buffers:
224TEST3foo3bar
224TEST3foo3bar224TEST3foo3bar
224TEST3foo3bar224TEST3foo
3bar224TEST3foo3bar
EDIT: I found this and this which lead me here. Vadym Stetsiak has cleared nearly everything up (his was one of the answers I was looking for).
This may or may not have anything to do with fragmentation.
In general, the socket will pass you as many bytes at a time as it feels like. Your job is to know how many bytes are in your overall message, and to read them all. Just keep looping until you have all the bytes you need, or until there's an exception.
The following code is untested right now. I thought I'd post it before writing the server side of it and testing both.
private static string ReceiveMessage(Socket socket)
{
const int BUFFER_SIZE = 1024;
var inputBuffer = new byte[BUFFER_SIZE];
var offset = 0;
var bytesReceived = socket.Receive(
inputBuffer, offset, BUFFER_SIZE - offset, SocketFlags.None);
if (bytesReceived < 2)
{
throw new InvalidOperationException("Receive error");
}
var inputMessageLength = inputBuffer[0]*256 + inputBuffer[1];
offset += bytesReceived;
var totalBytesReceived = bytesReceived;
while (bytesReceived > 0 &&
totalBytesReceived < inputMessageLength + 2)
{
bytesReceived = socket.Receive(
inputBuffer, offset, BUFFER_SIZE - offset, SocketFlags.None);
offset += bytesReceived;
totalBytesReceived += bytesReceived;
}
return Encoding.UTF8.GetString(
inputBuffer, 2, totalBytesReceived - 2);
}
Note that the receipt of the message length is wrong. The socket layer could give it to me a byte at a time. I'm going to revisit that as part of a refactoring that will receive the count into a separate two-byte buffer, and change the loop into a single do/while.
When you have to do it yourself, it can be done like so (reference here):
///
/// Server state holds current state of the client socket
///
class AsyncServerState
{
public byte[] Buffer = new byte[512]; //buffer for network i/o
public int DataSize = 0; //data size to be received by the server
//flag that indicates whether prefix was received
public bool DataSizeReceived = false;
public MemoryStream Data = new MemoryStream(); //place where data is stored
public SocketAsyncEventArgs ReadEventArgs = new SocketAsyncEventArgs();
public Socket Client;
}
///
/// Implements server receive logic
///
private void ProcessReceive(SocketAsyncEventArgs e)
{
//single message can be received using several receive operation
AsyncServerState state = e.UserToken as AsyncServerState;
if (e.BytesTransferred <= 0 || e.SocketError != SocketError.Success)
{
CloseConnection(e);
}
int dataRead = e.BytesTransferred;
int dataOffset = 0;
int restOfData = 0;
while (dataRead > 0)
{
if (!state.DataSizeReceived)
{
//there is already some data in the buffer
if (state.Data.Length > 0)
{
restOfData = PrefixSize - (int)state.Data.Length;
state.Data.Write(state.Buffer, dataOffset, restOfData);
dataRead -= restOfData;
dataOffset += restOfData;
}
else if (dataRead >= PrefixSize)
{ //store whole data size prefix
state.Data.Write(state.Buffer, dataOffset, PrefixSize);
dataRead -= PrefixSize;
dataOffset += PrefixSize;
}
else
{ // store only part of the size prefix
state.Data.Write(state.Buffer, dataOffset, dataRead);
dataOffset += dataRead;
dataRead = 0;
}
if (state.Data.Length == PrefixSize)
{ //we received data size prefix
state.DataSize = BitConverter.ToInt32(state.Data.GetBuffer(), 0);
state.DataSizeReceived = true;
state.Data.Position = 0;
state.Data.SetLength(0);
}
else
{ //we received just part of the headers information
//issue another read
if (!state.Client.ReceiveAsync(state.ReadEventArgs))
ProcessReceive(state.ReadEventArgs);
return;
}
}
//at this point we know the size of the pending data
if ((state.Data.Length + dataRead) >= state.DataSize)
{ //we have all the data for this message
restOfData = state.DataSize - (int)state.Data.Length;
state.Data.Write(state.Buffer, dataOffset, restOfData);
Console.WriteLine("Data message received. Size: {0}",
state.DataSize);
dataOffset += restOfData;
dataRead -= restOfData;
state.Data.SetLength(0);
state.Data.Position = 0;
state.DataSizeReceived = false;
state.DataSize = 0;
if (dataRead == 0)
{
if (!state.Client.ReceiveAsync(state.ReadEventArgs))
ProcessReceive(state.ReadEventArgs);
return;
}
else
continue;
}
else
{ //there is still data pending, store what we've
//received and issue another BeginReceive
state.Data.Write(state.Buffer, dataOffset, dataRead);
if (!state.Client.ReceiveAsync(state.ReadEventArgs))
ProcessReceive(state.ReadEventArgs);
dataRead = 0;
}
}
}
I did not do it exactly this way myself but it helped.