I'm building a C# client that connects to a render application and failing dismally! I narrowed the problem down by dissecting a python client that does work to this line:
def Startclient_Click(self, sender, e):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, int(port)))
message = b'message "Render"'
msg = struct.pack('<l',len(message))+struct.pack('<l',0)+message
#print(msg)
s.sendall(msg)
data = s.recv(1024)
data.decode("utf-8")
self.datatxt.Text ="data: " +str(data)
s.close()
return
except:
self.datatxt.Text ="No Server Connection"
return
What would the equivalent be in C#? From my understanding it needs 8 bytes before the message.
struct.pack takes a format followed by a series of values that will be packed according to the format. In your question you call:
struct.pack('<l', len(message))+struct.pack('<l',0)+message
Which is saying "Pack the length of this message as a little-endian long followed by a zero packed as a little-endian long followed by appending the rest of my message".
When you approach this kind of problem in C# we unfortunately do not have a direct port of struct.pack. Your closest equivalent would be to use either a BitConverter for one-off conversions like:
BitConverter.GetBytes((long)message.length) + BitConverter.GetBytes(0l) + message
or use a BinaryWriter into a MemoryStream. This brings yet another problem though which is that you cannot control the endian-ness using these tools. They expose "IsLittleEndian" so you know how they are acting but you cannot alter it.
Jon Skeet however is on the case - his MiscUtils library contains a LittleEndianBitConverter (MiscUtil.Conversion.LittleEndianBitConverter) that you can use or an EndianBinaryWriter should you go the Writer/MemoryStream route. So putting it all together, reference the MiscUtil library and use something like:
var bytes = new List<byte[]>(new[]
{
LittleEndianBitConverter.GetBytes(message.LongLength),
LittleEndianBitConverter.GetBytes(0l),
message
});
var msg = new byte[bytes.Sum(barray => barray.LongLength)];
int offset = 0;
foreach (var bArray in bytes)
{
System.Buffer.BlockCopy(bArray, 0, msg, offset, bArray.Length);
offset = bArray.Length;
}
The code is untested but should give you a reasonable starting point. It's assuming that your message is already a byte array and that msg is the array you want to return. We use System.Buffer.BlockCopy as it's the most efficient copy method for primitive types.
* EDIT *
I've taken the example in the question and mocked up a quick script in IDEOne for the Python code and its equivalent in C#. The kicker here is that the Struct.Pack('<l', 0)
call ignores the byte and does not add it to the output which may be what's tripping you up. This was causing the output to be 8 bytes too long.
Those scripts should point you in the right direction. If you're still having trouble can you post the code that you've tried.
For reference, the finished code in Python:
import struct
message = b'message "Render"'
msg = struct.pack('<l',len(message)) + struct.pack('<l',0) + message
print(":".join("{0:x}".format(ord(c)) for c in msg))
And in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MiscUtil.Conversion;
public class Test
{
public static void Main()
{
var message = Encoding.ASCII.GetBytes("message \"Render\"");
var lenc = new LittleEndianBitConverter();
var bytes = new List<byte[]>(new[]
{
lenc.GetBytes(message.LongLength),
message
});
var msg = new byte[bytes.Sum(barray => barray.LongLength)];
int offset = 0;
foreach (var bArray in bytes)
{
Buffer.BlockCopy(bArray, 0, msg, offset, bArray.Length);
offset = bArray.Length;
}
Console.WriteLine(BitConverter.ToString(msg).Replace("-", ":"));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With