Struct.Pack 等效于 C# 中

本文关键字:Pack Struct | 更新日期: 2023-09-27 18:35:09

我正在构建一个连接到渲染应用程序的 C# 客户端,但惨遭失败!我通过剖析一个确实适用于以下行的 python 客户端来缩小问题范围:

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

C# 中的等效项是什么?据我了解,在消息之前需要 8 个字节。

Struct.Pack 等效于 C# 中

struct.pack 采用一种格式,后跟一系列值,这些值将根据格式打包。在您的问题中,您致电:

struct.pack('<l', len(message))+struct.pack('<l',0)+message
这是说"将此消息的长度打包为小端长,然后打包为

零打包为小端长,然后附加我的其余消息"。

当你在C#中遇到这种问题时,不幸的是,我们没有struct.pack的直接端口。您最接近的等效方法是使用BitConverter进行一次性转换,例如:

BitConverter.GetBytes((long)message.length) + BitConverter.GetBytes(0l) + message

或者将 BinaryWriter 用于 MemoryStream。这带来了另一个问题,即您无法使用这些工具控制字节序。他们暴露了"IsLittleEndian",所以你知道他们的行为,但你不能改变它。

然而,Jon Skeet在这个案例上 - 他的MiscUtils库包含一个LittleEndianBitConverter(MiscUtil.Conversion.LittleEndianBitConverter),如果你使用Writer/MemoryStream路线,或者EndianBinaryWriter。因此,将它们放在一起,引用 MiscUtil 库并使用类似以下内容的内容:

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;
}

该代码未经测试,但应该为您提供一个合理的起点。假设您的消息已经是一个字节数组,并且 msg 是您要返回的数组。我们使用System.Buffer.BlockCopy,因为它是基元类型最有效的复制方法。

* 编辑 *

我以问题中的示例为例,并在 IDEOne 中模拟了一个快速脚本,用于 Python 代码及其在 C# 中的等效项。这里的踢球者是Struct.Pack('<l', 0)调用忽略字节,并且不会将其添加到输出中,这可能是绊倒您的原因。这导致输出太长 8 个字节。

这些脚本应该为您指明正确的方向。如果您仍然遇到问题,可以发布您尝试过的代码吗?

作为参考,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))

在 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("-", ":"));
    }
}