c# - C# 结构到字节数组封送产生 19 个元素而不是 20 个
问题描述
一个 UDP 服务器和客户端正在运行,并且在编译或运行时不会显示任何错误,除非给它超过 20 个字符。然后突然我在服务器端只返回了 19 个字符。
看起来SizeConst
字符串的 具有实际尺寸-1
。
当我发送字符串时,它会一直工作,直到我得到一个超过 20 个字符的字符串。尽管它只保留了 19 个字符SizeConst = 20
。(当 3 时只有 2 个字符,等等。)
有人可以解释为什么我突然丢失了一些数据吗?
/******************** STRUCT *****************************/
[StructLayout(LayoutKind.Sequential)]
public struct TEST
{
public string Buffer;
public int number;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string aString;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] innerTestArray;
}
/****************** CLIENT ********************************//
static void Main(string[] args)
{
//Start ServerSide acknowledge
byte[] resp = Encoding.ASCII.GetBytes("INIT");
sendData(resp);
while (true)
{
TEST test = new TEST();
Console.WriteLine("");
Console.WriteLine("ReadLine : ");
test.aString = Console.ReadLine();
test.number = 10;
test.innerTestArray = null;
test.Buffer = null;
byte[] arr = structToBytes(test);
sendData(arr);
}
}
/**************** MARSHAL FUNCTIONS *************************/
static byte[] structToBytes(object str)
{
byte[] arr = new byte[Marshal.SizeOf(str)];
IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(str));
Marshal.StructureToPtr(str, pnt, false);
Marshal.Copy(pnt, arr, 0, Marshal.SizeOf(str));
Marshal.FreeHGlobal(pnt);
return arr;
}
static TEST structFromBytes(byte[] arr)
{
TEST str = new TEST();
int size = Marshal.SizeOf(str);
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(arr, 0, ptr, size);
str = (TEST)Marshal.PtrToStructure(ptr, str.GetType());
Marshal.FreeHGlobal(ptr);
return str;
}
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
在这个例子中,我分配20
了SizeConstant
字符串。但是当我收到字符串时,它有一个SizeOf(string) = 19
.
此外,最好为字符串和其他数组提供更灵活的方法,以便具有更大的灵活性。IE不要SizeConst
在struc内使用。在这个例子中,我只有一些小数据,但后来我要发送的数据有很大差异。结构和不同数据类型的列表和数组。
任何提示,技巧,想法?
PS:演示代码在https://github.com/ritskes/C-UDP-struct-to-byte-DEMO-with-server-and-client
解决方案
发生这种情况是因为互操作假定字符串将以 null 结尾,因此编组添加了一个 null 终止符。这意味着字符串最长可以是 19 个字符,允许使用空终止符。
(请注意,文档实际上并未说明ByValTStr
将添加空终止符 - 但确实如此!)
以下可编译的控制台应用程序演示了该问题:
using System;
using System.Runtime.InteropServices;
namespace Demo
{
[StructLayout(LayoutKind.Sequential)]
public struct TEST
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string aString;
}
class Program
{
static void Main()
{
TEST test = new TEST();
test.aString = "1234567890123456789012345";
int size = Marshal.SizeOf(test);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(test, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Console.WriteLine("Bytes: " + string.Join(", ", arr));
test = Marshal.PtrToStructure<TEST>(ptr);
Marshal.FreeHGlobal(ptr);
Console.WriteLine(test.aString); // Prints "1234567890123456789" - only 19 characters.
}
}
}
解决方案可能是改用 char 数组:
using System;
using System.Runtime.InteropServices;
namespace Demo
{
[StructLayout(LayoutKind.Sequential)]
public struct TEST
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public char[] aString;
}
class Program
{
static void Main()
{
TEST test = new TEST();
test.aString = "1234567890123456789012345".ToCharArray();
int size = Marshal.SizeOf(test);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(test, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Console.WriteLine("Bytes: " + string.Join(", ", arr));
test = Marshal.PtrToStructure<TEST>(ptr);
Marshal.FreeHGlobal(ptr);
Console.WriteLine(new string(test.aString)); // Prints "12345678901234567890" - all 20 characters.
}
}
}
推荐阅读
- sockets - 自定义 UDP 协议的 sendto() 失败,使用 Seagull 协议流量生成器
- php - .zip 文件上传工具 aravel Laravel 5.6 Illuminate\Http\Exceptions\PostTooLargeException
- reactjs - 错误:在 React Native 安装期间被拒绝
- apache-spark - 从 ps 和 web-ui 隐藏 Spark 环境变量值
- google-cloud-platform - 有没有办法在 stackdrive 中跨服务跟踪作业?
- scala - Spark-Scala 将数字字符串转换为 Double
- wordpress - 向 Wordpress 页面添加功能
- c# - 用不同的标记分割字符串
- tensorflow - Tensorflow R-CNN 非常小的物体检测 - 比例和纵横比的最佳配置?
- python - 如何在 Pandas 中使用布尔索引