通过TCP套接字接收可变大小的数据
receiving variable size of data over TCP sockets
我在通过(TCP)套接字传输数据时遇到了一个小问题。关于我正在做的事情的小背景:
我将数据从A端发送到B端。发送的数据可以是可变长度的,假设最大大小为1096字节。
A) send(clientFd, buffer, size, NULL)
在B上,由于我不知道期望的大小,我总是尝试接收1096字节:
B) int receivedBytes = receive(fd, msgBuff, 1096, NULL)
然而,当我这样做的时候:我意识到A在发送小块数据。。比如大约80-90字节。在几次突发发送之后,B将它们组合在一起,接收字节数为1096。这显然破坏了数据,导致混乱。
为了解决这个问题,我将数据分为两部分:标头和数据。
struct IpcMsg
{
long msgType;
int devId;
uint32_t senderId;
uint16_t size;
uint8_t value[IPC_VALUES_SIZE];
};
A面:
A) send(clientFd, buffer, size, NULL)
在B上,我首先接收报头并确定要接收的有效载荷的大小:然后接收剩余的有效载荷。
B) int receivedBytes = receive(fd, msgBuff, sizeof(IpcMsg) - sizeof( ((IpcMsg*)0)->value ), 0);
int sizeToPoll = ((IpcMsg*)buffer)->size;
printf("Size to poll: %dn", sizeToPoll);
if (sizeToPoll != 0)
{
bytesRead = recv(clientFd, buffer + receivedBytes, sizeToPoll, 0);
}
所以,对于每一个有有效负载的发送,我都会调用receive两次。这对我很有效,但我想知道是否有更好的方法?
您的想法是正确的,发送一个包含以下数据的基本信息的标头,然后发送数据本身。然而,这并不总是有效的:
int receivedBytes = receive(fd, msgBuff, sizeof(IpcMsg) - sizeof( ((IpcMsg*)0)->value ), 0);
int sizeToPoll = ((IpcMsg*)buffer)->size;
原因是,TCP可以根据自己对应用于所谓拥塞控制策略的底层网络条件的评估,自由地将您的头分段并按其认为合适的数量发送。在局域网上,你几乎总是把你的头放在一个数据包里,但通过互联网在世界各地尝试,你一次可能会得到更少的字节数。
答案是不要直接调用TCP的"receive"(通常为recv
),而是将其抽象为一个小的实用程序函数,该函数占用了您真正必须接收的大小和一个缓冲区。进入接收和附加数据包的循环,直到所有数据到达或出现错误。
如果您需要异步并同时为多个客户端提供服务,则应用相同的主体,但您需要调查"select"调用,该调用允许您在数据到达时收到通知。
TCP/IP是用于发送数据的"原始"接口。它确实保证,如果发送了字节,它们都在那里,并且顺序正确,但对分块没有任何保证,对您发送的数据一无所知。
因此,如果通过TCP/IP发送要处理的"数据包",您必须通过以下技术之一知道何时拥有完整的数据包:
- 固定大小的数据包。在您的情况下为1096字节
- 首先发送/接收一个已知的"标头",它会告诉您发送的数据包的大小
- 使用某种"数据包结束"符号
在前两种情况下,您都知道期望接收的字节数,因此需要缓冲接收到的任何内容,直到收到完整的消息,然后进行处理。
如果您收到的数量超过预期,即溢出到下一个数据包中,则将其拆分,处理完成的数据包,并将剩余的数据包缓冲以供后续处理。
在后一种情况下,如果您有一个数据包结束符号,它可能在消息中的任何位置,所以它后面的任何东西都会缓冲下一个数据。
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- C++ TCP 套接字通信 - 连接按预期工作,几秒钟后失败,没有收到新数据,read() 和 recv() 块
- TCP 服务器的异步读取使用 boost::asio 打印客户端套接字发送的数据
- 如何查看async_accept故障的原始 tcp 数据?
- 如何使用 TCP 连接发送大块数据
- 通过TCP将数据从C++客户端发送到JSON服务器
- 如何将通过TCP发送数据的数据从C++转换为Java
- 从多个 tcp 连接读取数据
- Qt TCP服务器不从客户端读取数据
- TCP/IP - 以 C/C++ 格式发送十六进制数据包以控制中继板
- TCP 连接中的超时,没有数据交换
- TCP在客户端服务器之间传输时,数据是否有任何限制
- TOS字段从Linux的TCP插座上接收到的数据包获取
- 在服务器关闭的TCP连接上发送数据时的行为不一致
- 如何通过TCP/IP Winsock发送双型数据
- 了解 UDP 数据包大小限制的 TCP 数据包大小限制以及它在 boost::asio 编程级别的含义
- SOCAT,将TCP套接字转发到Unix套接字,将recvmsg()更改为read(),删除辅助数据
- 我们如何从BOOST :: ASIO :: TCP :: ip :: read_some呼叫中顺序接收多个数据
- TCP-Server以数据包结构(非Java客户端)发送文件
- 如何避免通过TCP/IP SSH隧道在数据传输中重复读取数据