我遇到了麻烦,我的服务器应用程序发送了 8 字节长度的数据包 -AABBCC1122334455
但我的应用程序分两部分接收此数据包,AABBCC1122
并且334455
通过“recv”功能,我该如何解决?
谢谢!
我遇到了麻烦,我的服务器应用程序发送了 8 字节长度的数据包 -AABBCC1122334455
但我的应用程序分两部分接收此数据包,AABBCC1122
并且334455
通过“recv”功能,我该如何解决?
谢谢!
总结一点:
send
和recv
都可以发送和接收比参数中提供的更少的数据。您必须正确处理它(通常通过在调用周围应用适当的循环)。从您已经提到的内容来看,您很可能想要发送某种消息(嗯,这通常是人们所做的)。关键是要正确发现消息的边界。如果您的消息是固定大小的,您只需从流中获取相同数量的数据并将其转换为您的消息;否则,您需要一种不同的方法:
如果你能想出一个在你的消息中不存在的字符,它可能是你的分隔符。然后,您可以阅读流,直到您到达角色,这将是您的消息。如果您传输 ASCII 字符(字符串),您可以使用零作为分隔符。
如果您传输二进制数据(原始整数等),所有字符都可以出现在您的消息中,因此没有任何内容可以充当分隔符。在这种情况下,最常见的方法可能是使用包含消息大小的固定大小前缀。这个额外字段的大小取决于消息的最大大小(使用 4 个字节可能是安全的,但如果您知道最大大小是多少,则可以使用较小的值)。然后您的数据包看起来像SSSS|PPPPPPPPP...
(字节流),其中S
是附加大小字段,并且P
是您的有效负载(应用程序中的真实消息,P
字节数由 的值确定S
)。您知道每个数据包都以 4 个特殊字节开头(S
字节),因此您可以将它们读取为 32 位整数。一旦知道封装消息的大小,就可以读取所有P
字节。处理完一个数据包后,您就可以从套接字读取另一个数据包了。
不过好消息是,你可以想出一些完全不同的东西。您只需要知道如何从字节流中反序列化您的消息以及如何send
/recv
行为。祝你好运!
编辑:
将任意数量的字节接收到数组中的函数示例:
bool recv_full(int sock, char *buffer, size_t size)
{
size_t received = 0;
while (received < size)
{
ssize_t r = recv(sock, buffer + received, size - received, 0);
if (r <= 0) break;
received += r;
}
return received == size;
}
以及接收具有 2 字节前缀定义有效负载大小的数据包的示例(有效负载大小限制为 65kB):
uint16_t msgSize = 0;
char msg[0xffff];
if (recv_full(sock, reinterpret_cast<char *>(&msgSize), sizeof(msgSize)) &&
recv_full(sock, msg, msgSize))
{
// Got the message in msg array
}
else
{
// Something bad happened to the connection
}
这就是recv()
在大多数平台上的工作方式。您必须检查收到的字节数并继续循环调用它,直到获得所需的数字。
您可以通过在循环中从 TCP 套接字读取来“修复”该问题,直到您获得足够的字节以对您的应用程序有意义。
我的服务器应用程序发送 8 字节长度的数据包
并不真地。您的服务器发送 8 个单独的字节,而不是 8 个字节长的数据包。TCP 数据通过字节流而不是数据包流发送。TCP 既不尊重也不维护您可能想到的任何“数据包”边界。
如果您知道您的数据是以 N 字节的数量提供的,则recv
在循环中调用:
std::vector<char> read_packet(int N) {
std::vector buffer(N);
int total = 0, count;
while ( total < N && (count = recv(sock_fd, &buffer[N], N-total, 0)) > 0 )
total += count;
return buffer;
}
std::vector<char> packet = read_packet(8);
如果您的数据包是可变长度的,请尝试在数据本身之前发送它:
int read_int() {
std::vector<char> buffer = read_packet(sizeof (int));
int result;
memcpy((void*)&result, (void*)&buffer[0], sizeof(int));
return result;
}
int length = read_int();
std::vector<char> data = read_buffer(length);