0

我正在尝试为程序制作套接字管理器。

我的问题是,为了我的需要,我需要从套接字检索确切数量的数据到缓冲区。

1) 使用静态数组

制作这样的静态缓冲区对我有用,但我不能总是知道要接收的数据的大小。

ubyte[2] buffer;
socket.receive(buffer);

这不起作用:

int size = buffer[0]; // for example ...
ubyte[size] buffer2; // crash at compilation because size is not known
socket.receive(buffer2);

所以我的第一个问题是:是否可以在编译时不知道其大小的情况下拥有静态数组?

我已经搜索了一种使用动态缓冲区的方法,但我遇到了其他问题。

2)使用切片从缓冲区中提取数据

ubyte[] buffer;
socket.receive(buffer);
ubyte[2] header = buffer[0..2];

这可行,但是如何从主缓冲区中删除提取的切片?使用带有元组的 std.algorithm 中的 remove 函数,这样:

buffer = remove(buffer,tuple(0,2));

对我不起作用我不知道为什么,我在编译时遇到此错误:

错误:未定义的标识符元组

这里有什么问题 ?

此外,我的套接字是非阻塞的,因为我希望它是异步的。如果套接字同时尝试在其上推送数据,则在主缓冲区上执行删除会导致问题?

感谢您阅读我,并为我糟糕的英语感到抱歉,我不是母语人士。

4

1 回答 1

2

警告:我以前没有使用过 std.socket,所以这是未经测试的。我对 C 中的套接字有经验,对 D 有一般经验,但还没有一起使用这两者;)

这只是您想要的猜测,但这里有:

import std.socket;
import std.bitmanip;

Socket socket = new Socket(AddressFamily.INET, SocketType.STREAM);
// ... bind, connect, etc ...
ubyte[2] header;
socket.receive(header);
ushort size = std.bitmanip.bigEndianToNative!ushort(header);
ubyte[] content = new ubyte[size];
socket.receive(content);
// ... do your stuff ...

您需要以某种方式知道传入数据的大小,即使在运行时也是如此。在我的示例中,大小包含在流中出来的前 2 个字节中。使用这些信息,我们动态分配一个缓冲区来保存其余部分。为简单起见,此示例是同步的:它假设接收将阻塞,直到内容被填充。这个例子也公然忽略了返回值,这很糟糕,但我很简单。

由于您打算进行异步通信,因此您可能需要编写自己的接收函数,该函数根据需要多次调用接收来填充缓冲区,或者如果不满足您定义的某些条件则中止。

在您的示例 1 中,问题正是您所期望的:如果不知道编译时的大小,就无法在编译时(静态数组)调整大小。

那么你的问题的答案是否定的,在编译时不知道它们的大小就不可能拥有静态数组。

在您的示例 2 中,“ubyte[] 缓冲区;” 在传递给接收之前被初始化为 null。这可能会给你一个断言崩溃或段错误。通常当 D 中的函数请求缓冲区时,它会期望内存已经分配;该函数的职责是用您想要的所有好东西填充已经分配的内存。唯一的例外可能是如果参数被声明为 ref,例如:“void foo(ref ubyte[] buffer)”,这表明如果你不这样做,函数将为你分配缓冲区(需要 ref来实现这一点)。这就是为什么我的示例在从 receive() 获取内容之前进行“新 ubyte [size]”评估的原因。

要回答有关切片的问题,这是分割数组的简单方法:

ubyte[] someArray = myArraySource();
ubyte[] header = someArray[0 .. 2];
someArray = someArray[2 .. $]; // Remove the "header" by slicing out everything else.

回答你的最后一个问题:不,它不应该引起问题。你应该没事。

详细信息:对于通过套接字进行双向通信,我认为您的缓冲区操作对套接字本身并不重要。您应该能够在不影响套接字的情况下从主缓冲区中“删除”内容,因为套接字不会保留对该缓冲区的任何引用。这是您的缓冲区,因为您分配了它(我希望如此)。这也不取决于套接字的同步与异步性质;只是套接字不太关心您的缓冲区。一旦你接收/发送了你的字节,那么套接字已经完成了它的工作,至少在下次调用它之前。

希望有帮助!

于 2013-04-28T15:34:44.513 回答