An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
How handle text and binary data in "ReceiveCallback"?
I had mirrored in @andrew code's in this question:
Cause a connected socket to accept new messages right after .BeginReceive?
to implement a more efficient version where we can receive not only text, but also binary data (like images).
In this moment i'm working in a android > C# (windows) connection (already handle big endian) where after some changes, the referred code seems make the promissed in that moment; but when i try receive a PNG image (remote screen) the header size not is received first and the data jumps immediately to "second" code block > if ((cDataLength + dataRead) >= c.DataSize){}.
Only after it, image size is received on "first" code block, but with very strange number for example:
- 167,45 KB expected (sent correctly by android)
- 41,9 MB received
Seems that to binary data not is necessary handle endianness because the first chunk of image is good, but the nexts are strange data and program starts to fail; even after remove the code related to endianness.
Then, why this is happennig and how fix?
Here is all relevant code:
class Client
{
public Socket socket;
public string RemoteAddress = "";
public byte[] Buffer = new byte[1024];
public int DataSize = 0;
public int PrefixSize = 0;
public bool DataSizeReceived = false;
public bool lengthRead = false;
public MemoryStream Data = new MemoryStream();
public Client(Socket socket)
{
this.socket = socket;
RemoteAddress = socket.RemoteEndPoint.ToString();
}
}
private void ReceiveCallback(IAsyncResult ar)
{
int dataOffset = 0;
int restOfData = 0;
int dataRead = 0;
Boolean StreamClosed = false;
long cDataLength = 0;
long LastcDataLength = 0;
SocketError socketError = SocketError.TypeNotFound;
Client c = (Client)ar.AsyncState;
if (!c.socket.Connected)
{
// Not Connected anymore ?
return;
}
try
{
dataRead = c.socket.EndReceive(ar, out socketError);
}
catch (Exception)
{
// Your code goes here..
return;
}
if (socketError != SocketError.Success)
{
// Has connection been lost ?
return;
}
if (dataRead <= 0)
{
// Has connection been lost ?
return;
}
while (dataRead > 0)
{
if (!c.DataSizeReceived)
{
if (!c.lengthRead)
{
byte[] BodyLengthR = new byte[4];
Array.Copy(c.Buffer, BodyLengthR, 4);
Int32 Endian = BitConverter.ToInt32(BodyLengthR, 0);
Int32 BodySize = BinaryPrimitives.ReverseEndianness(Endian);
c.PrefixSize = BodySize + 4;
Console.WriteLine("PrefixSize = " + Utils.SizeSuffix(c.PrefixSize));
Array.Resize(ref c.Buffer, c.PrefixSize);
c.lengthRead = true;
}
if (c.Data.Length > 0)
{
restOfData = c.PrefixSize - (int)c.Data.Length;
c.Data.Write(c.Buffer, dataOffset, restOfData);
dataRead -= restOfData;
dataOffset += restOfData;
}
else if (dataRead >= c.PrefixSize)
{
c.Data.Write(c.Buffer, dataOffset, c.PrefixSize);
dataRead -= c.PrefixSize;
dataOffset += c.PrefixSize;
}
else
{
c.Data.Write(c.Buffer, dataOffset, dataRead);
dataOffset += dataRead;
dataRead = 0;
}
if (c.Data.Length == c.PrefixSize)
{
c.DataSize = c.PrefixSize;
c.DataSizeReceived = true;
c.Data.Position = 0;
c.lengthRead = false;
//===========================================================================
string textRecv = Encoding.UTF8.GetString(c.Data.GetBuffer(), 0, c.DataSize);
if (textRecv.Contains("TEXT"))
{
// Handle the received messsage
}
if (textRecv.Contains("IMAGE"))
{
// Handle the received messsage
}
//==========================================================================
c.Data.SetLength(0);
}
else
{
c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
return;
}
}
try
{
cDataLength = c.Data.Length;
LastcDataLength = cDataLength;
}
catch (ObjectDisposedException)
{
StreamClosed = true;
}
if (!StreamClosed)
{
if ((cDataLength + dataRead) >= c.DataSize)
{
restOfData = c.DataSize - (int)c.Data.Length;
c.Data.Write(c.Buffer, dataOffset, restOfData);
// Handle the received messsage
//===========================================================================
string textRecv = Encoding.UTF8.GetString(c.Data.GetBuffer(), 0, (int)c.Data.Length);
if (textRecv.Contains("TEXT"))
{
// Handle the received messsage
}
if (textRecv.Contains("IMAGE"))
{
int index = textRecv.IndexOf("IMAGE");
byte[] bytes = Utils.RemoveAt(c.Data.ToArray(), 0, index); // index + 5 (save to file)
/*
string Recv = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
Console.WriteLine(Recv);
Image img = (Bitmap)((new ImageConverter()).ConvertFrom(bytes));
var img2 = new Bitmap(img);
img2.Save("C:\\Users\\Eu\\Desktop\\Test.png", ImageFormat.Png);
*/
}
//==========================================================================
dataOffset += restOfData;
dataRead -= restOfData;
c.Data = new MemoryStream();
c.Data.Position = 0;
c.DataSizeReceived = false;
c.DataSize = 0;
if (dataRead == 0)
{
if (_IsConnected(c.socket))
{
c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
return;
}
}
else
continue;
}
else
{
if (_IsConnected(c.socket))
{
c.Data.Write(c.Buffer, dataOffset, dataRead);
c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
dataRead = 0;
}
}
}
else
{
if (LastcDataLength + dataRead == c.DataSize)
{
if (_IsConnected(c.socket))
{
c.socket.BeginReceive(c.Buffer, 0, c.Buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), c);
}
return;
}
else
{
}
}
if (!_IsConnected(c.socket))
dataRead = -1;
}
}
private bool _IsConnected(Socket socket)
{
try
{
return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException)
{
return false;
}
}