【问题标题】:C++ winsock send arraysC++ winsock 发送数组
【发布时间】:2014-08-07 01:29:40
【问题描述】:

我正在尝试使用 winsock2 通过网络发送数组。现在,我读到微软禁用了发送原始指针,但您仍然可以通过将指针转换为 char* 来发送未经编辑的二进制数据:

send(rsock, (char*)&counter, len, 0);

但是,问题是当数据到达客户端时将数据放回数组中。这里,pass 是二进制数据。这就是我处理整数、布尔值和双精度数的方式。

    recv(sock, pass, sizeof(int), 0);
    refresh =  (int((void*)&pass));
    recv(sock, pass, sizeof(bool[4800][254]), 0);
    **key = (bool)&pass;
    recv(sock, pass, sizeof(double[4800][254]), 0);
    **mil = (double)&pass;

整数不是数组,而 bool 和 doubles 存储在二维数组中。现在,编译器说这段代码适用于 int 和 bool 但对于双打它说“'type cast' : cannot convert from 'char **' to 'double'” “无效的类型转换”,即使我试图将原始数据放入其中。我做错了什么吗?还有其他解决方法来发送数组吗?提前致谢。

编辑:另外,我还没有在另一台 PC 上尝试过代码,所以我非常怀疑整数和布尔值的转换是否正确。

【问题讨论】:

  • 您到底在哪里“读到 [that] Microsoft 禁止发送原始指针”?你可以发送任何你喜欢的东西。在接收者那里它是否意味着任何东西是另一个问题。
  • 我不记得我读到了什么确切的问题,但它在堆栈溢出 - 顺便说一句,send(rsock, &counter, len, 0); 不能编译,我必须使用 send(rsock, (char)&counter, len, 0);*。 char后面还有一个乘号,但是网站格式不显示。
  • 你读错了,或者记错了。除了这个问题之外,整个网站上的“Microsoft 禁用发送原始指针”都没有匹配项。您的问题与编译错误有关, 而不是“Microsoft 禁用发送原始指针”。
  • 好吧,考虑到我记错了,你有关于发送问题或演员表问题的任何线索吗?谢谢。
  • 不存在“发送问题”。有一个转换问题,这只是 C 编程,并且您的 recv() 代码存在问题:您假设它填充了缓冲区。它没有签订这样做的合同。需要将recv()的结果存入一个变量,检查为-1,检查为0,否则作为接收的字节数;如果下一段代码足够了,OK,否则循环。

标签: c++ arrays pointers networking winsock2


【解决方案1】:

Microsoft 没有禁用发送任何内容。事实是,发送指针对远程对等点毫无用处。指针只是一个内存地址,如果没有信息,知道地址是没有用的。

您可能面临的问题是这个数组太大而无法容纳发送缓冲区,默认情况下只能容纳 64KB。

注意send()recv() 的返回值,以了解您在该交易中实际读取/发送了多少数据。它并不总是与您告诉函数执行的大小相同,因为它通常被分成小于 4KB 的部分。您必须管理这些信息的传输,以填充整个阵列。

【讨论】:

  • 你是对的,但我在这个问题中谈论的问题不是指针没有到达客户端,我正在寻找一种将指针拉回数组的方法,看到我尝试过的那个适用于布尔值,但由于某种我不知道的原因而不适用于双打。
  • @Alex 您看到的问题是您认为可以将指针转换为数据的问题。这不是它的工作方式。您所做的是通过套接字发送 data (不是指针),然后接收方必须获取该数据并在该端重新创建数据结构。假设您正在尝试将数据保存到文件中,然后在另一个程序中读取该文件并重构数据。你会怎么做?原理是一样的。
【解决方案2】:

我做错了吗?

嗯……

  • 默认情况下,sendrecv 不保证仅在所有您提供的缓冲区发送或接收后返回;一旦他们将更多数据排入队列以进行发送,或者在收到您可能能够处理的更多数据后,他们可能会立即返回......提供的缓冲区大小只是您请求的上限,而不是最低限度。如果要确保 recv 在填充完整缓冲区之前不会返回,请添加 MSG_WAITALL 标志作为最终参数。对于send,您必须循环发送输出缓冲区的更多部分。

  • 检查您返回的代码...sendrecv 会告诉您错误,并且只有很少的数字可以为您提供有关原因和解决方案的线索

  • “编译器说这段代码有效”——不,它没有……它说你的代码请求了它准备编译的东西,充满了它不打算尝试验证的强制转换,大部分这将在运行时崩溃

然后是这个:

recv(sock, pass, sizeof(int), 0);
refresh =  (int((void*)&pass));
recv(sock, pass, sizeof(bool[4800][254]), 0);
**key = (bool)&pass;
recv(sock, pass, sizeof(double[4800][254]), 0);
**mil = (double)&pass;

我什至不打算开始说这一切有什么问题......让我们来谈谈可能起作用(可能将在下面讨论):

template <typename T>
void get(int sock, T& t)
{
    if (recv(sock, (char*)&t, sizeof t, MSG_WAITALL) != sizeof t)
        throw std::runtime_error("error while reading data from socket");
}

int refresh;
get(refresh);

bool key[4800][254];
get(key);

double mil[4800][254];
get(mil);

如果您的发送和接收系统、编译器、编译器标志、可执行文件等有任何不同,那么这可能无论如何都不起作用:

  • 直到 C++03 编译器不需要使用任何特定类型来存储 bool,所以谁知道您的发送端和接收端是否匹配

  • big endian 和 little endian 系统具有不同的字节顺序,这可能会破坏像这样的幼稚二进制传输

  • int 的大小可能会有所不同

最终,更可靠的方法是使用 boost 序列化库。

【讨论】:

  • 我理解您的失望,但这不应该是最终代码,一旦演员表起作用,我就会检查返回。无论如何,谢谢,我会按照你的提示。哦。你确定 boost 序列化库可以在 socket 上工作吗?
  • @Alex:不客气。重新提升序列化和套接字 - 现有问题中有一些答案/链接 - 例如here。干杯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
相关资源
最近更新 更多