我试图通过winsock UDP套接字从客户端发送到服务器,但是我没有收到已发送的相同字节,或者至少没有正确地重新组装结构。
struct Header
{
uint16_t sender;
uint16_t number;
uint16_t packetSize;
uint16_t type;
};
发送struct:
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,5428,52428。
在发送/接收过程中是否有我遗漏的内容,或者是否在另一端创建结构?
答案 0 :(得分:2)
首先,通过网络发送原始结构是非常不可移植的:
除非在特殊情况下您可以确定发送方和接收方共享相同的体系结构,操作系统和编译器,从不这样做。
通常的方法是使用可移植格式,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 *
。
答案 1 :(得分:0)
您可以使用:#pragma pack(show)
将对齐打印为警告,并确保它是相同的。
如果存在差异,请使用#pragma pack(n)
,如下所示:
#pragma pack(push)
#pragma pack(1)
struct Header{
...
};
#pragma pack(pop)
您不必将memcpy
结构缓冲。你可以直接使用你的标题对象。