C++ Winsock 结构发送/接收

标签 c++ sockets struct winsock2

我正在尝试通过 winsock UDP 套接字从客户端向服务器发送一个结构,但我没有收到已发送的相同字节,或者至少没有正确地重新组装该结构。

struct Header
{
  uint16_t sender;
  uint16_t number;
  uint16_t packetSize;
  uint16_t type; 
};

发送结构:

Header header;
header.sender = 1;
header.number = 2;
header.packetSize = 3;
header.type = 4;

char buffer[sizeof(Header)];
memcpy(buffer, &header, sizeof(Header));

 int bytesSent = sendto(sendSocket_, data, sizeof(Header), 0, (const sockaddr*)&sendSocketAddr_, sizeof(sendSocketAddr_));
  if (bytesSent > 0)
  {
    cout << bytesSent << endl;
  }

接收结构:

char *data = new char[sizeof(Header)];
  int bytesRecv = recv(listenSocket_, data, sizeof(Header), 0);
  if (bytesRecv > 0)
  {
    cout << bytesRecv << endl;
    Header header;
    memcpy(&header, data, sizeof(data));
    cout << header.sender << ": " << header.number << ": " << header.packetSize << ": " << header.type << endl;
}

接收的字节数与发送的字节数相同,但是一旦复制回服务器端的新结构,只有前两个值是正确的,其余的则不正确。

在这种情况下,接收到的结构包含 1、2、52428、52428。

我在发送/接收过程中是否遗漏了什么,或者是否与在另一端创建结构有关?

最佳答案

首先,通过网络发送原始结构是高度不可移植的:

  • 您可以在发送方和接收方之间设置字节顺序差异
  • 您可以在发送方和接收方之间设置对齐差异

除非在特殊情况下您可以确定发送方和接收方共享相同的体系结构、操作系统和编译器,否则永远不要这样做

通常的方法是使用可移植格式,ASCII(健壮但通常不是最优的)或二进制格式,但您必须定义明确的表示形式。例如,当您使用 4 uint16_t 时:

包装:

char buffer[8];
buffer[0] = header.sender >> 8; /* or (header.sender >> 8) & 0xFF if longer ...*/
buffer[1] = header.sender & 0xFF;
buffer[2] = header.number >> 8;
...

解压:

header.sender = (buffer[0] << 8) | buffer[1];
header.number = (buffer[2] << 8) | buffer[3];
...

但是如果你有不同架构的问题,你就不会得到前两个值。您当前的问题要简单得多:在接收代码时,您有:

char *data = new char[sizeof(Header)];
....
    memcpy(&header, data, sizeof(data));

sizeof(data)sizeof(char *),在 32 位机器中是 4 个字节,而 sizeof(Header)是 4 * 2 = 8 个字节。

你应该改为:

    memcpy(&header, data, sizeof(Header));

顺便说一句,您可以避免 memcpy 部分。

发件人部分:

int bytesSent = sendto(sendSocket_, &header, sizeof(Header), 0, (const sockaddr*)&sendSocketAddr_, sizeof(sendSocketAddr_));

有效,因为 sendto 的第二个参数是 const void * 并且自动转换为 void *

接收者:

int bytesRecv = recv(listenSocket_, &header, sizeof(Header), 0);

因为 recv 的第二个参数实际上是一个 void *

关于C++ Winsock 结构发送/接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28668956/

相关文章:

通过 Sockets 的 Java 文件传输修剪最后字节

sockets - 当套接字连接中的一个端点断开连接时会发生什么

c++ - 什么时候调用复制构造函数

c++ - 结合 GMPXX 和 C++11 及更高版本

c++ - 如何定义一个使用命名空间的全局结构,以便使用该结构的文件不使用此命名空间? C++

sockets - 为什么许多库没有检测到无效的TCP连接?

struct - Racket 契约(Contract)和结构问题

go - 具有动态类型的结构

go - 解码 JSON 对象并将值映射到 Go 中的结构

c++ - 为什么我点击的次数越多,我的 qt 应用程序就越慢?