C++ Winsock struct send/recv
C++ Winsock struct send/recv
我正试图通过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);
因为CCD_ 9的第二个自变量实际上是CCD_。
您可以使用:#pragma pack(show)
将对齐打印为警告并确保其相同。
如果有差异,使用#pragma pack(n)
,如下所示:
#pragma pack(push)
#pragma pack(1)
struct Header{
...
};
#pragma pack(pop)
您不必memcpy
要缓冲的结构。您可以直接使用您的头对象。
相关文章:
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- Linux 服务器中的 Recv 缓冲区大小
- 在 for 循环中处理复杂的发送 recv 消息
- 在UNIX中通过recv/send交换数据时,如何正确使用缓冲区
- Epoll zero recv() and negative(EAGAIN) send()
- send() 或 recv() 未同步
- 如果send()返回x字节,则recv()在一个呼叫中获取相同数量的字节
- VS 2010 c++ Express 无法链接 recv() 和 send()
- send()和recv()套接字参数
- C++ Winsock struct send/recv
- Recv-Q+Send-Q>写字节
- 不能很好地与send()和recv()一起使用,短字符串的第一个字节丢失了.c++
- 线程由函数 send() 或 ACE_SOCK_Stream的 recv() 停止
- recv()/send()(在Socket中)或read()/write(在CFile中)中出错
- 将recv()和send()的缓冲区从C#传递到C++
- 以某种方式在ZMQ中同时使用Send/Recv是可能的(通过多线程)
- C/pp套接字,recv()/send()只在gdb下工作
- WinSock2:使用recv和send在单独的线程中处理接受的传入连接
- Send() and recv() double or int
- 使用Winsock的send()/recv()时是否需要确认响应