Am sending texture data over UDP for an LED project. Am wondering if there’s a way to convert the whole integer list (texture RGB information) to the byte array that’s needed by the UDP method. Currently I loop through it and cast each int to a byte, which works, but if there’s a faster way that would be great to know.
void sendNumberList(int[] message)
{
byte[] byteMessage = new byte[message.Length];
// Is there a way to convert the whole array at once instead of looping through it?
for (int i = 0; i < message.Length; i++)
{
byteMessage[i] = ((byte)message[i]);
}
try
{
client.Send(byteMessage, byteMessage.Length, remoteEndPoint);
print("message " + message + " sent to " + remoteEndPoint);
}
catch (Exception err)
{
print(err.ToString());
}
}
No problem as of yet, and probably won’t have any if the lists aren’t super-long. But I did see there’s a built-in method for doing this for string messages, so was wondering if there’s an equivalent one. That said, not sure how much faster any of these actually are under the hood, especially if they iterate through the lists anyway.
Yeah, I saw that one a bit ago. Not sure if it was what I needed, when it said it would get 4 bytes out of each int though. I’m just looking to send the 0-255 value directly, so technically it’s an 8-bit int.
Casting int to byte will limit the value of each int to the max value of a byte, which I believe is a range from -127 to +127, or similar (edit: sorry it is 0-255 ). I’m not sure what happens to values outside of that range, but they won’t be correct. What you should do is serialize/deserialize, so you preserve all values of the int array.
Quick example off the top of my head below. Writing it directly into the forums, so might be a typo or two. But this way preserves the entire range of values of the integers.
using system;
//convert an integer array into a byte array, with the integer array length as a 4 byte header
public byte[] IntArrayToByteArray(int[] intArray)
{
int totalBytes = (intArray.Length * 4) + 4; //Integers are 4 bytes long, plus we're going to add another integer at the beginning with the total array length
byte[] serialized = new byte[totalBytes]; //Byte array we are going to return
List<byte[]> listOfBytes = new List<byte[]>(); //A temporary list of byte arrays of converted integers
foreach (int i in intArray)
{
byte[] converted = BitConverter.GetBytes(i); //convert an integer into a 4 length byte array
listOfBytes.Add(converted);
}
//Now lets build the final byte array
int location = 0; //track our current location within the byte array we are going to return with this
Array.Copy(BitConverter.GetBytes(intArray.Length), 0, serialized, location, 4); //include the length of the integer array as a header in front of the actual data
location += 4;
foreach (byte[] ba in listOfBytes) //now add the contents of the list to the byte array
{
Array.Copy(ba, 0, serialized, location, 4);
location +=4;
}
return serialized;
}
//deserialize byte array back to an integer array
//the provided byte array is a 4 byte header of an integer which represents the integer array length, followed by the serialized contents of the entire integer array
public int[] byteArrayToIntArray(byte[] serialized)
{
int location = 0;
//first we get the int array length that we serialized to the start of the byte array
int length = BitConverter.ToInt32(serialized, location);
location += 4;
int[] intArray = new int[length];
int index = 0;
while (index < length) //Now lets reconstruct the original integer array
{
intArray[index] = BitConverter.ToInt32(serialized, location);
location += 4;
index++;
}
return intArray;
}
Thanks everyone! I’ve got a version that seems to work fine. I don’t think any bottlenecks will be at this end anyways, it’s more about UDP packet sizes and rate of transfer. Will test it on the LED hardware soon and see.
Since UdpClient.Send can only accept byte arrays (and has no pointer overloads), there’s unfortunately no way to safely avoid copying the data. With that in mind, the most efficient way to convert from int[ ] to byte[ ] should be the following:
var result = new byte[input.Length * sizeof(int)];
Buffer.BlockCopy(input, 0, result, 0, result.Length);
I’d suggest allocating a single byte[ ] array with your largest expected size, and reusing it for future Send calls to keep your allocations down (since Send can accept a data size).
Also keep in mind that none of these solutions (mine included) account for endianness, which requires additional code to handle properly.
Hmm, didn’t work, it’s inserting 3 0’s after each value in the list. Without the *sizeof(int) it does the same, but only 8 values total are printed.
{ 0, 10, 50, 100, 150, 200, 250, 255 } // just for testing
List out is
{ 0, 0, 0, 0, 10, 0 0 0 }
Also, curious, any reason you used
var result
instead of
byte[ ] result?
Well, if your test array is still an int array, that’d be correct (little endianness in your case).
int32 split into bytes for your test array:
0 => 0, 0, 0, 0
10 => 10, 0, 0, 0
50 => 50, 0, 0, 0
and so on
If your test array contained values greater than 255, it’d continue like this:
256 => 0, 1, 0, 0
257=> 1, 1, 0, 0
…
300 => 44, 1, 0, 0
The last argument tells the method how many bytes to copy. Since an int in C# (System.Int32) consists of 4 bytes, you want to copy the number of integers * size of an integer. Your test array contains 8 values, hence you want to copy 8 * 4 bytes = 32 bytes.
If you remove the sizeof(int), it won’t magically copy only one byte of each of those integers, instead it’ll start at the supplied start index and copy 8 contiguous bytes, which is the length of 2 ints. So yes, the result looks the same (at least the 8 bytes it copied), but now you’ve only copied a quarter of the bytes contained in the int array.
There’s no difference. As long as the compiler can infer the type from the context (e.g. when you do an assignment), you’ll be able to use it. But you don’t have to. Note that this is usually turning into an endless debate about pros and cons of var versus using explicit types - better don’t start it.
Ok cool, that makes sense, thanks for the clarification. There are a few holes in my understanding of the basic data types and endianness. In my case I only need 8-bit ints, so now I’m just using a byte array to start with. Should be all good.