C# 中的 Struct.Pack 等价物?

Posted

技术标签:

【中文标题】C# 中的 Struct.Pack 等价物?【英文标题】:Struct.Pack Equivalent in C#? 【发布时间】:2022-01-15 18:11:46 【问题描述】:

我正在构建一个连接到渲染应用程序的 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 个字节。

【问题讨论】:

第一个参数告诉它哪种打包方式是你最可能的问题......我认为('&lt;l')意味着 lsb 在最左边......但我很容易错了 更多参考 - ***.com/questions/1818242/… 【参考方案1】:

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

struct.pack('<l', len(message))+struct.pack('<l',0)+message

这就是说“将此消息的长度打包为 little-endian long,然后将零打包为 little-endian long,然后附加我的其余消息”。

当您在 C# 中处理此类问题时,很遗憾我们没有 struct.pack 的直接端口。您最接近的等价物是使用BitConverter 进行一次性转换,例如:

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

或将BinaryWriter 转换为MemoryStream。这带来了另一个问题,即您无法使用这些工具控制字节序。他们公开了“IsLittleEndian”,因此您知道他们的行为方式,但您无法更改它。

Jon Skeet 然而,他的MiscUtils 库包含一个您可以使用的 LittleEndianBitConverter (MiscUtil.Conversion.LittleEndianBitConverter) 或一个 EndianBinaryWriter,如果您使用 Writer/MemoryStream 路线。所以把它们放在一起,参考 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 code 及其equivalent in C# 模拟了一个快速脚本。这里的关键是Struct.Pack('&lt;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("-", ":"));
    

【讨论】:

感谢您的回复,有机会我会尽快回复您:) 遗憾的是,我仍然遇到问题,我已经用工作的 wpf Ironpython 版本更新了我的原始帖子,老实说,我认为这将涉及到有人使用 Thea 渲染测试 c# 版本,我不不要指望任何人下载他们永远不会使用的 100meg 应用程序。至少在我找到答案之前,我有一个 python 可以做一些原型设计:) @NigeC, C# 中的(origsize, cmpsize, ) = unpack('&lt;LL', catrec) 可以等价于什么

以上是关于C# 中的 Struct.Pack 等价物?的主要内容,如果未能解决你的问题,请参考以下文章

C# 中的 C++ 内存复制等价物

C# 中的 C++ 模板继承等价物是啥?

C# 中的 Java matchesAt() 等价物

java中的C#填充权等价物? [复制]

C# 中的 Java RuntimeException 等价物?

C++ 中的 <map> 的 C# 等价物是啥? [复制]