Related
In my application every packet has 2 bytes length on the start. However after some time application starts receiving length less than zero. In synchronous client everything works correctly, but it's too slow. I'm 100% sure in Server everything is correct.
Connect:
public void Connect(IPAddress ip, int port)
{
tcpClient.Connect(ip, port);
stream = tcpClient.GetStream();
byte[] len_buffer = new byte[2];
stream.BeginRead(len_buffer, 0, len_buffer.Length, OnDataRead, len_buffer);
}
OnDataRead:
private void OnDataRead(IAsyncResult ar)
{
byte[] len = ar.AsyncState as byte[];
int length = BitConverter.ToInt16(len, 0);
byte[] buffer = new byte[length];
int remaining = length;
int pos = 0;
while (remaining != 0)
{
int add = stream.Read(buffer, pos, remaining);
pos += add;
remaining -= add;
}
Process(buffer);
len = new byte[2];
stream.EndRead(ar);
stream.BeginRead(len, 0, len.Length, OnDataRead, len);
}
As I can see, you're mixing up synchronious and asynchronious. That's a bad practice.
What you want is something like:
var header = ReadHeader(); // 2 bytes
var data = ReadData(header.DataSize);
I didn't use the network stream, but....
Here's an example of my async SocketReader:
public static class SocketReader
{
// This method will continues read until count bytes are read. (or socket is closed)
private static void DoReadFromSocket(Socket socket, int bytesRead, int count, byte[] buffer, Action<ArraySegment<byte>> endRead)
{
// Start a BeginReceive.
try
{
socket.BeginReceive(buffer, bytesRead, count - bytesRead, SocketFlags.None, (asyncResult) =>
{
// Get the bytes read.
int read = 0;
try
{
// if this goes wrong, the read remains 0
read = socket.EndReceive(asyncResult);
}
catch (ObjectDisposedException) { }
catch (Exception exception)
{
Trace.TraceError(exception.Message);
}
// if zero bytes received, the socket isn't available anymore.
if (read == 0)
{
endRead(new ArraySegment<byte>(buffer, 0, 0));
return;
}
// increase the bytesRead, (position within the buffer)
bytesRead += read;
// if all bytes are read, call the endRead with the buffer.
if (bytesRead == count)
// All bytes are read. Invoke callback.
endRead(new ArraySegment<byte>(buffer, 0, count));
else
// if not all bytes received, start another BeginReceive.
DoReadFromSocket(socket, bytesRead, count, buffer, endRead);
}, null);
}
catch (Exception exception)
{
Trace.TraceError(exception.Message);
endRead(new ArraySegment<byte>(buffer, 0, 0));
}
}
public static void ReadFromSocket(Socket socket, int count, Action<ArraySegment<byte>> endRead)
{
// read from socket, construct a new buffer.
DoReadFromSocket(socket, 0, count, new byte[count], endRead);
}
public static void ReadFromSocket(Socket socket, int count, byte[] buffer, Action<ArraySegment<byte>> endRead)
{
// if you do have a buffer available, you can pass that one. (this way you do not construct new buffers for receiving and able to reuse buffers)
// if the buffer is too small, raise an exception, the caller should check the count and size of the buffer.
if (count > buffer.Length)
throw new ArgumentOutOfRangeException(nameof(count));
DoReadFromSocket(socket, 0, count, buffer, endRead);
}
}
Usage:
SocketReader.ReadFromSocket(socket, 2, (headerData) =>
{
if(headerData.Count == 0)
{
// nothing/closed
return;
}
// Read the length of the data.
int length = BitConverter.ToInt16(headerData.Array, headerData.Offset);
SocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
{
if(dataBufferSegment.Count == 0)
{
// nothing/closed
return;
}
Process(dataBufferSegment);
// extra: if you need a binaryreader..
using(var stream = new MemoryStream(dataBufferSegment.Array, dataBufferSegment.Offset, dataBufferSegment.Count))
using(var reader = new BinaryReader(stream))
{
var whatever = reader.ReadInt32();
}
}
});
You can optimize the receive buffer by passing a buffer (look at the overloads)
Continues receiving: (reusing receivebuffer)
public class PacketReader
{
private byte[] _receiveBuffer = new byte[2];
// This will run until the socket is closed.
public void StartReceiving(Socket socket, Action<ArraySegment<byte>> process)
{
SocketReader.ReadFromSocket(socket, 2, _receiveBuffer, (headerData) =>
{
if(headerData.Count == 0)
{
// nothing/closed
return;
}
// Read the length of the data.
int length = BitConverter.ToInt16(headerData.Array, headerData.Offset);
// if the receive buffer is too small, reallocate it.
if(_receiveBuffer.Length < length)
_receiveBuffer = new byte[length];
SocketReader.ReadFromSocket(socket, length, _receiveBuffer, (dataBufferSegment) =>
{
if(dataBufferSegment.Count == 0)
{
// nothing/closed
return;
}
try
{
process(dataBufferSegment);
}
catch { }
StartReceiving(socket, process);
});
});
}
}
Usage:
private PacketReader _reader;
public void Start()
{
_reader = new PacketReader(socket, HandlePacket);
}
private void HandlePacket(ArraySegment<byte> packet)
{
// do stuff.....
}
I need to simulate a stream using a file...
This is what I was able to produce so far... the code works, but the streaming does not occur.
I have no experience with streams, so expect to find lot of bugs.
Stream chunkedStream = new MemoryStream();
var task = session.AnalyzeAsync(chunkedStream);
FillStream(chunkedStream);
while (!task.Wait(500))
{
Console.Write("\r" + ((float)chunkedStream.Position / 16000) + " Seconds");
if (!chunkedStream.CanWrite)
{
break;
}
}
private static async Task FillStream(Stream chunkedStream)
{
var stream = Properties.Resources.ResourceManager.GetStream("Sample");
byte[] chunk = new byte[16000];
while (true)
{
Thread.Sleep(1000);
int index = 0;
// There are various different ways of structuring this bit of code.
// Fundamentally we're trying to keep reading in to our chunk until
// either we reach the end of the stream, or we've read everything we need.
while (index < chunk.Length)
{
int bytesRead = stream.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
break;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
// SendChunk(chunk, index); // index is the number of bytes in the chunk
chunkedStream.Write(chunk, 0, chunk.Length);
}
if (index != chunk.Length) // We didn't read a full chunk: we're done
{
chunkedStream.Close();
return;
}
}
}
public async Task AnalyzeAsync(Stream voiceStream)
{
IntervalHandler();
_StreamTask = UpStreamVoiceData(voiceStream);
await _StreamTask;
}
private async Task<Result<AnalysisResult>> UpStreamVoiceData(Stream voiceStream)
{
HttpWebRequest webRequest = WebRequestExtensions.CreateJsonPostRequest(_actions.upStream);
webRequest.ReadWriteTimeout = 1000000;
webRequest.Timeout = 10000000;
webRequest.SendChunked = true;
webRequest.AllowWriteStreamBuffering = false;
webRequest.AllowReadStreamBuffering = false;
using (var requeststream = webRequest.GetRequestStream())
{
await voiceStream.CopyStreamWithAutoFlush(requeststream);
requeststream.Close();
}
return webRequest.ReadJsonResponseAs<Result<AnalysisResult>>();
}
I am working on a new machine at my works which is controlled via a PC. Current stuck on talking to a camera system that is connected via Ethernet.
Here is my code of opening a connection.
TcpClient client;
NetworkStream stream;
public bool OpenConnection()
{
client = new TcpClient();
try
{
//Camera.Open();
client.Connect("192.168.0.10", 8500);
stream = client.GetStream();
}
catch (Exception ex)
{
return false;
}
return true;
}
So far so good. Once the connection is open I then request some information from the camera
The message format I am using has STX(0x02) to indicate the start of the message and ETX(0x03) as the end of the message.
char StartOfPacket = (char)0x02;
char EndOfPacket= (char)0x03;
public bool RetrieveDigits(out string Digits)
{
// Send the trigger cammand to the vision system
Digits = "";
bool EverythingOK = true;
string DataToSend = StartOfPacket + "T1" + EndOfPacket;
byte[] buff = Encoding.ASCII.GetBytes(DataToSend);
if (LogCameraEvent != null)
LogCameraEvent(">> " + DataToSend);
try
{
stream.Write(buff, 0, buff.Length);
}
catch (Exception ex)
{
Logging.Instance.LogExceptionToFile(MethodBase.GetCurrentMethod(), ex);
EverythingOK = false;
}
Thread.Sleep(100);
byte[] buffer;
if (EverythingOK)
{
// Check the response
buffer = ReadCamera(10);
// Process the packets
string[] packets = ProcessPackets(buffer);
if (packets != null)
{
if (packets.Length > 0)
{
bool TriggerFound = false;
for (int i = 0; i < packets.Length; i++)
{
if (packets[i] == "T1")
{
TriggerFound = true;
continue;
}
else if (TriggerFound)
{
// If we are here then we should now be the data that was requested
if (string.IsNullOrEmpty(packets[i]))
{
Digits = packets[i-1]; // previous packet may have data from previous trigger. Need to look into why this happens.
}
else
Digits = packets[i];
EverythingOK = true;
break;
}
else
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
else
{
Console.WriteLine("No Packets Recieved");
EverythingOK = false;
}
}
return EverythingOK;
}
Here is the part where I think the issue may lie, getting the response.
private byte[] ReadCamera(int ExpectedLength)
{
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
int chunk;
while(stream.DataAvailable)
{
chunk = stream.Read(Buffer, read, Buffer.Length-read);
read += chunk;
// If we have reached the end of our buffer, check to see if theres any more information
if(read == Buffer.Length)
{
if(!stream.DataAvailable)
return Buffer;
// Nope. Resize the buffer, put the byte we've just read and continue
byte[] newBuffer = new byte[Buffer.Length * 2];
Array.Copy(Buffer, newBuffer, Buffer.Length);
Buffer = newBuffer;
//read++;
}
else if(!stream.DataAvailable)
return Buffer;
Thread.Sleep(50);
}
// Buffer is now too big, shrink it
byte[] ret = new byte[read];
Array.Copy(Buffer, ret, read);
return ret;
}
private string[] ProcessPackets(byte[] data)
{
// look for the stat char
List<string> Packets = new List<string>();
byte Start = 0x02;
bool StartFound = false;
byte End = 0x03;
StringBuilder sb = new StringBuilder();
for(int i =0; i<data.Length; i++)
{
if(StartFound)
{
// Check to see if its the end
if (data[i] == End)
{
Packets.Add(sb.ToString());
sb.Clear();
}
else
sb.Append(Encoding.ASCII.GetChars(data, i, 1));
}
// Find the start
if (!StartFound)
{
if (data[i] == Start)
{
StartFound = true;
}
}
}
return Packets.ToArray();
}
Let me explain what should happen and then what is happening. Through RetrieveDigits method I am sending "T1" to the camera. What the camera will do is respond with "T1" followed by 2 ascii characters, for now we will say AA. Using a diagnostic app on the camera system I can monitor the Ethernet and I see the following.
(>> means Received by Camera)
(<< means Sent from Camera)
>>[STX]T1[ETX]
<<[STX]T1[ETX][STX]AA[ETX]
So I see what the camera has sent. I confirmed the PC has has received the data using wire shark.
Now further down in the RetrieveDigits method you can see I process the packets received, loop through the packets until I find "T1" and then assume the next packet will be the data I am after and I set Digits to this value.
What I am finding is that sometimes when I run the app I see that Digits is set to "".
I am also finding that sometimes my data received will be "AA" then "T1" rather than "T1" then "AA". What I suspect is happening is that when its back to front, the "AA" is actually from the previous data sent from the camera and for some reason it was missed when reading from the stream.
Any idea why this could be happening as I am reading the data until Stream.Available is false.
Edit:
Modified the ReadCamera code to process the packets, reading 1 byte at a time.
private string[] ReadCamera(int ExpectedLength, int ExpectedPackets)
{
List<string> Packets = new List<string>();
bool StartFound = false;
StringBuilder sb = new StringBuilder();
if(ExpectedLength < 1)
{
ExpectedLength = 100;
}
byte[] Buffer = new byte[ExpectedLength];
int read = 0;
while (true)
{
read += stream.Read(Buffer, read, 1);
// Check to see if the byte read is the start of a packet
if (Buffer[read - 1] == StartOfPacket)
{
StartFound = true;
}
else if (StartFound)
{
// Check to see if the byte read is the end of a packet
if (Buffer[read - 1] == EndOfPacket)
{
Packets.Add(sb.ToString());
sb.Clear();
StartFound = false;
if (Packets.Count == ExpectedPackets)
break;
}
else
{
sb.Append(Encoding.ASCII.GetChars(Buffer, read - 1, 1));
}
}
}
// For Debuggin purposes
foreach(string s in Packets)
if (LogCameraEvent != null)
LogCameraEvent("<< " + s);
return Packets.ToArray();
}
and modified calling the method like so
// Check the response
string[] packets = ReadCamera(10,2);
// Process the packets
//string[] packets = ProcessPackets(buffer);
What I'm trying to do is to received a large number of bytes (about 5MB data) sent from the client side
Below is the code where data(byte[]) is received
byte[] receivedBytesRaw = new byte[4000];
//first, initialize network stream
NetworkStream stream = client.GetStream();
//The bytesNeeded is the size of bytes which is a protocol sent by the client side indicating the size of byte which will be sent
int bytesNeeded = 4000;
int bytesReceived = 0;
do
{
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded - bytesReceived);
networkValidation.addBytesToList(receivedBytesRaw, ref receivedBytes);
bytesReceived += bytesRead;
} while (bytesReceived < bytesNeeded);
But now I'm stuck on a problem:
Everytime when data arrives, the do while loop loops for the first time, and the return value (i) is 26, then it loops again, this time, when it goes to " i = stream.Read(receivedBytesRaw, 0, receivedBytesRaw.Length);", the program seems waiting for the client side to send data and have no response, also, when I check "receivedBytesRaw", the data was incomplete, only the first 13 bytes was received, the remaining space in the byte array remains null, and the stream.DataAvailable is false
Why the server side received incomplete data?
Note: when I try to send small data (a string), it's ok
=====================================================================
Edited
Below is the client side code which sends data:
private int sendData(byte[] dataSend, string IP, int portNumber)
{
TcpClient clientSide = new TcpClient();
int result = -1;
try
{
clientSide.Connect(IP, portNumber);
}
catch (Exception ex)
{
return 2;
}
NetworkStream netStream = clientSide.GetStream();
if (netStream.CanWrite)
{
byte[] replyMsg = new byte[1024];
netStream.Write(dataSend, 0, dataSend.Length);
netStream.Flush();
result = 0;
}
else
{
result = 1;
}
return result;
}
Because it's a stream, and can be partial received. Are you sure you are always receiving packages with te size of 2048 bytes?
int i = 0;
int bytesNeeded = 200;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded);
I think you need a frame protocol, try create a protocol like, writing the size of the data that follows.
example: (psuedo)
void SendData(byte[] data)
{
// get the 4 bytes of a int value.
byte[] dataLength = BitConverter.GetBytes(data.Lenght);
// write the length to the stream.
stream.Write(dataLength, 0, dataLength.Length);
// write the data bytes.
stream.Write(data, 0, data.Length);
}
void Receive()
{
// read 4 bytes from the stream.
ReadBuffer(buffer, 4);
// convert those 4 bytes to an int.
int dataLength = BitConverter.ToInt32(buffer, 0);
// read bytes with dataLength as count.
ReadBuffer(buffer, dataLength);
}
// read until the right amount of bytes are read.
void ReadBuffer(byte[] buffer, int length)
{
int i = 0;
int bytesNeeded = length;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(buffer, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded); // <- you should do this async.
}
This is just an example..
Another solution you could try is using async reads.
I made a class that reads until all bytes are read. If it isn't a problem that the complete file is read, you could try this:
Example:
This example show that you can read a simple protocol. ReadPacket handles a length + data message. So the sender will first send an int value containing the length of data that follows.
The StartReading method reads a filename and the filedata. It will store up to 10mb max filesize. But this isn't originally designed for receiving files.
const int MaxFileSize = 10 * 1024 * 1024;
private void Example()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("localhost", 12345);
StartReading(socket);
}
private void StartReading(Socket socket)
{
ReadPacket(socket, (filenameData) =>
{
if (filenameData.Count == 0)
{
// disconnected
return;
}
// parse the filename
string filename = Encoding.UTF8.GetString(filenameData.Array, filenameData.Offset, filenameData.Count);
Trace.WriteLine("Receiving file :" + filename);
ReadPacket(socket, (fileData) =>
{
if (fileData.Count == 0)
{
// disconnected
return;
}
Trace.WriteLine("Writing file :" + filename);
// write to the file
using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
stream.Write(fileData.Array, fileData.Offset, fileData.Count);
// start waiting for another packet.
StartReading(socket);
});
});
}
private void ReadPacket(Socket socket, Action<ArraySegment<byte>> endRead)
{
// read header. (length of data) (4 bytes)
EasySocketReader.ReadFromSocket(socket, 4, (headerBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (headerBufferSegment.Count == 0)
{
// disconnected;
endRead(new ArraySegment<byte>());
return;
}
// Get the length of the data that follows
int length = BitConverter.ToInt32(headerBufferSegment.Array, headerBufferSegment.Offset);
// Check the length
if (length > MaxFileSize)
{
// disconnect
endRead(new ArraySegment<byte>());
return;
}
// Read bytes specified in length.
EasySocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (dataBufferSegment.Count == 0)
{
endRead(new ArraySegment<byte>());
return;
}
endRead(dataBufferSegment);
});
});
}
The EasySocketReader class can be found on my blog: http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/
The original EasyPacketReader can be found here: http://csharp.vanlangen.biz/network-programming/async-sockets/easypacketreader/
For the sending part, you could use something like this:
private void SendFile(Socket socket, string filename)
{
byte[] filenameData = Encoding.UTF8.GetBytes(filename);
socket.Send(BitConverter.GetBytes(filenameData.Length));
socket.Send(filenameData);
int fileSize;
byte[] fileData;
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
fileSize = (int)stream.Length;
if (fileSize > MaxFileSize)
throw new ArgumentOutOfRangeException("File too big");
fileData = new byte[fileSize];
stream.Read(fileData, 0, fileSize);
}
socket.Send(BitConverter.GetBytes(fileSize));
socket.Send(fileData);
}
I'm currently in a little bit of a pickle. I have some code that reads data from a socket whenever data is available but currently it is in a while loop on a separate thread and chews through 50% of the CPU when the function returns because of no data available. What I would really like is a blocking function for Sockets that blocks until data is available, or at least a OnData event that could be listened on. I originally converted this code from AS3 (Flash) but their sockets class has the OnData event I need... just in the wrong language.
I currently have this code in the code that handles a client connecting:
ServerThread = new Thread(() =>
{
while (server.Connected && ServerContinue)
{
ReceiveFromServer(server, client);
}
Disconnect(server, client, false);
});
ServerThread.Start();
And this is the code in ReceiveFromServer:
bool isReady = false;
int messageLength = 0;
int dataAvailable = 0;
UInt16 packetSize = 0;
byte[] temp = new byte[2];
do
{
dataAvailable = server.Available;
if (isReady)
{
if (dataAvailable >= messageLength)
{
byte[] temp1 = new byte[2000];
int bytesRead = server.Receive(temp1, 0, messageLength, SocketFlags.None);
byte[] data = new byte[bytesRead + 2];
Buffer.BlockCopy(temp1, 0, data, 2, messageLength);
Helpers.ByteArray tempo = data;
tempo.writeByte(temp[1]);
tempo.writeByte(temp[0]);
if (!VersionCheckPass)
{
Send(tempo, client);
return;
}
ServerPacketHandler(tempo, client);
messageLength = 0;
isReady = false;
temp = new byte[2];
}
}
else if(dataAvailable > 2)
{
server.Receive(temp, 0, 2, SocketFlags.None);
temp = temp.Reverse().ToArray();
packetSize = BitConverter.ToUInt16(temp, 0);
if (packetSize > 0)
{
messageLength = packetSize;
isReady = true;
}
}
}
while (dataAvailable > 2 && dataAvailable >= messageLength && ServerContinue);
But the issue here is that when dataAvailable is 0 the function simply returns, and then RecevieFromServer is called again in the thread. This means that alot of the CPU is used by simply calling ReceiveFromServer and then returning again.
I currently have Thread.Sleep(10) after ReceiveFromServer in the ServerThread but this is inefficient. So my question is, Is there a way to block until data is available or is there an event that I can handle? Or does anyone else have any suggestions on how to do the same thing I am currently doing but it doesn't loop endlessly whilst there is no data available.
Found a really easy (and obvious) solution to block until data is available. Call Socket.Receive with a receive size of 0. The socket blocks until there is data to receive, then reads 0 bytes from the socket, and unblocks. Its really quite marvelous :) Heres how I implemented it:
ServerThread = new Thread(() =>
{
byte[] zero = new byte[0];
while (Server.Connected && ServerContinue)
{
server.Receive(zero, 0, SocketFlags.None);
ReceiveFromServer(server, client);
}
Disconnect(server, client, false);
});
Thanks for all the help.
Josh
There is not a lot of re-write needed. Your code looks like it's just receiving the message and then passing off to another routine to process it.
My reply to this thread pretty much covers what you're wanting to do:
C# Sockets and Multithreading
My socketReadCallBack function is:
private void OnDataReceived(IAsyncResult asyn)
{
ReceiveState rState = (ReceiveState)asyn.AsyncState;
Socket client = rState.Client;
SocketError socketError = SocketError.TypeNotFound;
if (!client.Connected)
{
// Not Connected anymore ?
return;
}
_LastComms = DateTime.Now;
_LastIn = _LastComms;
int dataOffset = 0;
int restOfData = 0;
int dataRead = 0;
Boolean StreamClosed = false;
long rStateDataLength = 0;
long LastrStateDataLength = 0;
try
{
dataRead = client.EndReceive(asyn, out socketError);
}
catch (Exception excpt)
{
// Handle error - use your own code..
}
if (socketError != SocketError.Success)
{
// Has Connection been lost ?
OnConnectionDropped(client);
return;
}
if (dataRead <= 0)
{
// Has connection been lost ?
OnConnectionDropped(client);
return;
}
while (dataRead > 0)
{
//check to determine what income data contain: size prefix or message
if (!rState.DataSizeReceived)
{
//there is already some data in the buffer
if (rState.Data.Length > 0)
{
restOfData = PrefixSize - (int)rState.Data.Length;
rState.Data.Write(rState.Buffer, dataOffset, restOfData);
dataRead -= restOfData;
dataOffset += restOfData;
}
else if (dataRead >= PrefixSize)
{ //store whole data size prefix
rState.Data.Write(rState.Buffer, dataOffset, PrefixSize);
dataRead -= PrefixSize;
dataOffset += PrefixSize;
}
else
{ // store only part of the size prefix
rState.Data.Write(rState.Buffer, dataOffset, dataRead);
dataOffset += dataRead;
dataRead = 0;
}
if (rState.Data.Length == PrefixSize)
{ //we received data size prefix
rState.DataSize = BitConverter.ToInt32(rState.Data.GetBuffer(), 0);
rState.DataSizeReceived = true;
//reset internal data stream
rState.Data.Position = 0;
rState.Data.SetLength(0);
}
else
{ //we received just part of the prefix information
//issue another read
client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
SocketFlags.None, new AsyncCallback(socketReadCallBack),
rState);
return;
}
}
//at this point we know the size of the pending data
// Object disposed exception may raise here
try
{
rStateDataLength = rState.Data.Length;
LastrStateDataLength = rStateDataLength;
}
catch (ObjectDisposedException Ode)
{
StreamClosed = true;
}
if (!StreamClosed)
{
if ((rStateDataLength + dataRead) >= rState.DataSize)
{ //we have all the data for this message
restOfData = rState.DataSize - (int)rState.Data.Length;
rState.Data.Write(rState.Buffer, dataOffset, restOfData);
//Console.WriteLine("Data message received. Size: {0}",
// rState.DataSize);
// Is this a heartbeat message ?
if (rState.Data.Length == 2)
{
// Yes
HeartBeatReceived();
}
else
{
//charArray = new char[uniEncoding.GetCharCount(
//byteArray, 0, count)];
//uniEncoding.GetDecoder().GetChars(
// byteArray, 0, count, charArray, 0);
//Console.WriteLine(charArray);
//rState.Data.Position = 0;
DecodeMessageReceived(GetStringFromStream(rState.Data));
}
dataOffset += restOfData;
dataRead -= restOfData;
//message received - cleanup internal memory stream
rState.Data = new MemoryStream();
rState.Data.Position = 0;
rState.DataSizeReceived = false;
rState.DataSize = 0;
if (dataRead == 0)
{
//no more data remaining to process - issue another receive
if (_IsConnected)
{
client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
SocketFlags.None, new AsyncCallback(socketReadCallBack),
rState);
return;
}
}
else
continue; //there's still some data to process in the buffers
}
else
{ //there is still data pending, store what we've
//received and issue another BeginReceive
if (_IsConnected)
{
rState.Data.Write(rState.Buffer, dataOffset, dataRead);
client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
SocketFlags.None, new AsyncCallback(socketReadCallBack), rState);
dataRead = 0;
}
}
}
else
{
// Stream closed, but have we read everything ?
if (LastrStateDataLength + dataRead == rState.DataSize)
{
// We're equal, get ready for more
//no more data remaining to process - issue another receive
if (_IsConnected)
{
client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
SocketFlags.None, new AsyncCallback(socketReadCallBack),
rState);
}
return;
}
else
{
// We should have more..
// Report Error
}
}
// If we've been disconnected, provide a graceful exit
if (!_IsConnected)
dataRead = -1;
}
}
I've got a few more things in here than you need like provision for a heartbeat message and raising events on connection dropped etc.