receive bytes into an array from tcp client in c# - c#

I want to receive bytes into an array from tcp client. I've an array of bytes dataToRecieve, in which I'm receiving those bytes.
But I've got some problems here, can anyone check my code:
while (true) {
try {
Socket handler = mainSocket.Accept();
byte[] dataToRecieve = new byte[handler.ReceiveBufferSize];
int[] dataArray = new int[1024];
handler.Receive(dataToRecieve);
//////SOME CODE
int i = handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch(Exception) {}
--------//////some code
Now I want to receive bytes into byte array & than convert it into the int array (however the data should be in an int array)........

Well, your code already has a problem here:
handler.Receive(dataToRecieve);
You're ignoring the value returned by Receive, to tell you how many bytes were actually read. That's almost always a bad idea. Likewise you're assuming you receive all the information you need in a single call. Usually you'd either have to loop until you'd read all the data - either by knowing that you expect a certain amount, or by reading until there is no more data.
Once you've got the data into a byte array, converting it into an integer array depends on the format in the byte array. You may be able to just use Buffer.BlockCopy, but that's only if the endianness in the byte array matches the endianness in memory. Alternatively, you can simply create an array of the right size, and write a loop:
int[] integers = new byte[size / 4];
for (int i = 0; i < integers.Length; i++)
{
integers[i] = BitConverter.ToInt32(bytes, i * 4);
}
However, again you need to consider the endianness. My MiscUtil library has an EndianBitConverter class which allows you to specify the endianness of your data.

Related

Array of bytes[] has no values when is converted from int[]

I'm passing int[] array that hold image, later I want to convert it to bytes[] and save the image to local path. However, I notice that the bytePic[] length is equal to int[] arrPic just the values are missing. There is a screenshot below:
Below is the entire function:
public string ChangeMaterialPicture(int[] arrPic, int materialId,string defaultPath)
{
var material = _warehouseRepository.GetMaterialById(materialId);
if(material is not null)
{
// Convert the Array to Bytes
byte[] bytePic = new byte[arrPic.Length];
for(var i = 0; i < arrPic.Length; i++)
{
AddByteToArray(bytePic, Convert.ToByte(arrPic[i]));
}
// Convert the Bytes to IMG
string filename = Guid.NewGuid().ToString() + "_.png";
System.IO.File.WriteAllBytes(#$"{defaultPath}\materials\{material.VendorId}\{filename}", bytePic);
// Update the Image
material.Picture = filename;
_warehouseRepository.UpdateMaterial(material);
return material.Picture;
}
else
{
return String.Empty;
}
}
public byte[] AddByteToArray(byte[] bArray, byte newByte)
{
byte[] newArray = new byte[bArray.Length + 1];
bArray.CopyTo(newArray, 1);
newArray[0] = newByte;
return newArray;
}
You are creating the new array newArray in AddByteToArray and return it. But at the call site you are never using this returned value and the bytePic array remains unchanged.
The code in AddByteToArray makes no sense. Why create a new array when the intention was to insert one byte into an existing array? What you need to do is to cast the int into byte. Simply write:
byte[] bytePic = new byte[arrPic.Length];
for (int i = 0; i < arrPic.Length; i++)
{
bytePic[i] = (byte)arrPic[i];
}
And delete the method AddByteToArray.
This assumes that every value in the int array is in the range 0 to 255 and therefore fits into one byte.
There are different ways to do this. With LINQ you could also write:
byte[] bytePic = arrPic.Select(i => (byte)i).ToArray();
I would assume your original array uses a int to represent a full RGBA-pixel, since 32bit per pixel mono images are very rare in my experience. And if you do have such an image, you probably want to be more intelligent in how you do this conversion. The only time just casting int to bytes would be a good idea is if you are sure only the lower 8 bits are used, but if that is the case, why are you using an int-array in the first place.
If you actually have RGBA-pixles you do not want to convert individual int-values to bytes, but rather convert a single int value to 4 bytes. And this is not that difficult to do, you just need to use the right methods. The old school options is to use Buffer.BlockCopy.
Example:
byte[] bytePic = new byte[arrPic.Length * 4];
Buffer.BlockCopy(arrPic, 0, bytePic, 0, bytePic.Length);
But if your write-method accepts a span you might want to just convert your array to a span and cast this to the right type, avoiding the copy.

Same integer lists, different byte arrays

I have a question about interesting thing that happened to me when I have tried to convert elements of List<short> to byte[] in C#.
Firstly, I had to read large binary file, which contains 262144 short type signed numbers. I have read the file and build list of numbers with the following code:
byte[] content = null;
content = File.ReadAllBytes(scanName);
List<int> transformed = new List<int>();
for (int n = 0; n < content.Length; n += 2) // 2 bytes
{
short sample = BitConverter.ToInt16(content, n);
transformed.Add(sample);
}
Then I have compressed and decompressed numbers with algorithm and got back same values, which seemed right. The problems occurs when try to convert both lists to byte arrays. This has been done by following method:
private byte[] ToByte(List<short> list){
List<byte> toRet = new List<byte>();
foreach(short s in list)
{
byte[] converted = BitConverter.GetBytes(s);
foreach(byte b in converted)
{
toRet.Add(b);
}
}
return toRet.ToArray();
}
But when I compared both byte arrays with first.SequenceEqual(second), the method returned false. Isn't it strange, because values in both lists are same?
At the end, I have solved the issue. The problem wasn't in converting short to byte, but in the part of code which hasn't been published there. Specifically, I made very beginner mistake, I converted 2D array into 1D array in the wrong way. Now everything works perfectly. Thank you for all your responses and sorry for inconveniences!

C# BinaryReader ReadBytes(len) returns different results than Read(bytes, 0, len)

I've got a BinaryReader reading in a number of bytes into an array. The underlying Stream for the reader is a BufferedStream(whose underlying stream is a network stream). I noticed that sometimes the reader.Read(arr, 0, len) method is returning different(wrong) results than reader.ReadBytes(len).
Basically my setup code looks like this:
var httpClient = new HttpClient();
var reader = new BinaryReader(new BufferedStream(await httpClient.GetStreamAsync(url).ConfigureAwait(false)));
Later on down the line, I'm reading a byte array from the reader. I can confirm the sz variable is the same for both scenarios.
int sz = ReadSize(reader); //sz of the array to read
if (bytes == null || bytes.Length <= sz)
{
bytes = new byte[sz];
}
//reader.Read will return different results than reader.ReadBytes sometimes
//everything else is the same up until this point
//var tempBytes = reader.ReadBytes(sz); <- this will return right results
reader.Read(bytes, 0, sz); // <- this will not return the right results sometimes
It seems like the reader.Read method is reading further into the stream than it needs to or something, because the rest of the parsing will break after this happens. Obviously I could stick with reader.ReadBytes, but I want to reuse the byte array to go easy on the GC here.
Would there ever be any reason that this would happen? Is a setting wrong or something?
Make sure you clear out bytes array before calling this function because Read(bytes, 0, len) does NOT clear given byte array, so some previous bytes may conflict with new one. I also had this problem long ago in one of my parsers. just set all elements to zero, or make sure that you are only reading (parsing) up to given len

Passing byte array through serialport

I want to pass the following byte array through serial port.
array[j].abc = 2;
array[j].def = 4;
array[j].gh = 6;
array[j].ij = 0;
array[j].jl = 1;
array[j].fg= 1;
array[j].bh = 2;
I passed the byte array as follow
byte[] wtbin = TestSerializer.StructureToByteArray(array[j]);
byte[] bharr = new byte[1];
bharr[0] = wtbin[i];
serialPort1.Write(bharr, 0, 1);
But serialport receives it as letters like B,B etc. How can
I receive it as numbers??
You can pass a whole byte array (generally named buffer) into the serialPort.Write() method. What you are doing instead is passing a single byte to the method. In your case the call to the method would be something like:
serialport1.Write(wtbin, 0, wtbin.Length);
You can read more about SerialPort on MSDN - SerialPort Write. Additionally keep in mind that you are sending bytes, not ASCII text. Depending on what you are sending PUTTY may display different things. In order to convert a byte array(buffer) back to ASCII, you can use
Encoding.ASCII.GetString(buffer);
Hope this helps :)

Asynchronous socket, receive string messages

Good evening, sorry in advance for writing so much but I don't know where the error is...
My client application is receiving from the server asynchronously. I want to transfer a bunch of stuff at once (the contents of an array, a couple of hundred bytes).
I want the server to be able to send "commands", and have a function on the client side act according to these commands, for example if the message from the server reads "print_hello", it should call a function that prints hello.
Now, it's my understanding that when receiving data asynchronously, I can't know how much of the data has been sent (or if more data than I expected has been sent), so I need to store all the data in a buffer, and when an "end of command" (for example, '!') sign has been received, it should know to call the function.
So far this makes sense to me, but I'm having trouble implementing it. In my DataReceived callback function, I have this code:
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
mainBuffer is declared as volatile static string mainBuffer = "";
The first line prints correctly, and goes through all of the data as expected. However, when I print out the mainBuffer, it only prints out the very first set of data I receieved, the rest does not get added to the buffer.
What could cause this? Thread safety issues? Am I not reading the latest value of mainBuffer? I can't use breakpoints to debug this.
Sample output:
Raw data: ABC
ABC
Raw data: DEF
ABC
RAW data: GHI
ABC
Small update, I tried using a volatile static int as well, and it increments and prints correctly after each DataReceived(). The string still does not get updated however.
Here is your problem "with the messing code lines!":
//of course the problem has noting to do with the string being volatile...
private volatile string mainBuffer = string.Empty;
byte[] buffer = new byte[1024];
while (networkStream.Read(buffer, 0, buffer.Length) > 0)
{
string data = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
}
Naturally the output of this code will be as you mentioned previously. Here is what is happening:
The string class in C# is an array of char start by pointer to the first char in the array and ends by the special "terminal" char \0.
When you create a byte array of n index, it will fill all indexes of the array with the default value of byte which is 0. but 0 is just equals the terminal char \0
byte b = (byte)`\0`;\\the value of b will be 0
So, When you call Read(buffer), the method will not trim the buffer to just fit the data read. so if the buffer size "here 1024" is larger than the data read, all the remaining bytes of the buffer will be equals to the terminal char '\0', So the array of chars of the generated string will be ABC\0\0\0\0... to the index 1024. When you add a string DEF to that it will add it at the last index of the char array "after last \0", the char array then will be ABC\0\0\0\0...DEF, but because of DEF is added after the terminal char(s) so the Console.Write will ignore all after the first \0!.
Also note while you debugging, if you point your mouse to the mainBuffer variable, you will see the actual data it contains maybe something like ABC\0\0\0\0..DEF\0\0\0\0..GHI
However to fix the problem and only generate a reliable string, Get the actual bytes read and generate the string only from it. So:
int dataRead = 0;
while ((dataRead = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
List<byte> actualBuffer = (new List<byte>(buffer)).GetRange(0, dataRead);
string data = System.Text.Encoding.UTF8.GetString(actualBuffer.ToArray());
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
}
It is wroth to mention here that you should consider using StringBuilder instead of string.

Categories

Resources