C++ C++;Winsock结构发送/接收

C++ C++;Winsock结构发送/接收,c++,sockets,struct,winsock2,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; heade

我试图通过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;
}
Header;
header.sender=1;
页眉编号=2;
header.packetSize=3;
header.type=4;
字符缓冲区[sizeof(头)];
memcpy(缓冲区和标头,sizeof(标头));
int bytesSent=sendto(sendSocket,data,sizeof(Header),0,(const sockaddr*)和sendSocketAddr,sizeof(sendSocketAddr));
如果(字节数>0)
{
cout您可以使用:
#pragma pack(show)
将对齐方式打印为警告并确保其相同

如果存在差异,请使用如下方式使用
#pragma pack(n)

#pragma pack(push)
#pragma pack(1)
struct Header{
  ...
};
#pragma pack(pop)

您不必
memcpy
将结构发送到缓冲区。您可以直接使用标头对象。

首先,通过网络发送原始结构非常不可移植:

  • 发送方和接收方之间可以存在端点差异
  • 您可以在发送方和接收方之间存在对齐差异
除非在特殊情况下,您可以确保发送方和接收方共享相同的体系结构、操作系统和编译器,永远不要这样做

通常的方法是使用可移植格式,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];
...
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*

客户端和服务器是否使用相同的编译器使用相同的选项编译?如果不是,则结构中字段的对齐方式可能不同。是的,客户端和服务器都使用相同的编译器使用相同的选项编译。我不确定大小是否正确为缓冲区数组分配e。memcpy中应该有
sizeof(header)
(变量的大小,而不是类型)。在发送之前打印出缓冲区的内容,以确保发送的内容正确。不要这样做。不要将结构用作网络协议。将网络协议用作网络协议。以八位字节定义有线格式,并为自己编写一个库来发送和接收。如果使用结构,则至少会引入六个dependenc是的。您是否尝试检查
bytesSent
的值是否等于
sizeof(Header)
?您还可以有填充差异或数据类型大小差异。所有这些都可能因硬件、操作系统、编译器、编译器版本、编译器标志、编译器选项、周围的#pragmas等等而有所不同。更不用说源代码本身了。使用此技术的唯一安全方法是确保两个对等体都是从源代码构建的相同的对象文件。
int bytesRecv = recv(listenSocket_, &header, sizeof(Header), 0);