我遇到了麻烦,我的服务器应用程序发送长度为8个字节的数据包 - AABBCC1122334455
但是我的应用程序通过“recv”函数分两部分AABBCC1122
和334455
接收此数据包我能解决这个问题吗?
谢谢!
答案 0 :(得分:5)
总结一下liitle:
send
和recv
都可以发送和接收的数据少于参数中提供的数据。你必须正确处理它(通常通过在呼叫周围应用适当的循环)。从你已经提到的内容来看,你很可能想要发送某种消息(好吧,这通常是人们所做的)。关键是要正确发现消息的边界。如果您的邮件大小固定,您只需从流中获取相同数量的数据并将其转换为您的邮件;否则,你需要一个不同的方法:
如果你能想出一个在你的信息中不存在的角色,它可能是你的分界符。然后,您可以阅读流,直到您到达角色,这将是您的消息。如果您传输ASCII字符(字符串),则可以使用零作为分隔符。
如果您传输二进制数据(原始整数等),所有字符都可以出现在您的消息中,因此没有任何字符可以作为分隔符。在这种情况下,最常见的方法可能是使用包含邮件大小的固定大小的前缀。这个额外字段的大小取决于消息的最大大小(4个字节可能是安全的,但如果知道最大大小是什么,则可以使用较低的值)。然后您的数据包看起来像SSSS|PPPPPPPPP...
(字节流),其中S
是附加大小字段,P
是您的有效负载(应用程序中的真实消息,{{1}字节由P
)的值确定。您知道每个数据包都以4个特殊字节(S
字节)开头,因此您可以将它们作为32位整数读取。一旦知道封装消息的大小,就会读取所有S
个字节。完成一个数据包后,您就可以从套接字中读取另一个数据包了。
好消息,你可以想出一些完全不同的东西。您需要知道的是如何从字节流中反序列化您的消息以及P
/ send
的行为方式。祝你好运!
修改强>
将任意数量的字节接收到数组中的函数示例:
recv
接收带有2字节前缀的数据包的示例,定义了有效载荷的大小(有效载荷的大小限制为65kB):
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;
}
答案 1 :(得分:1)
这就是recv()
在大多数平台上的工作原理。您必须检查收到的字节数并继续在循环中调用它,直到获得所需的数字。
答案 2 :(得分:0)
通过从循环 中的TCP套接字 读取“修复”,直到您获得足够的字节来理解您的应用程序。
答案 3 :(得分:0)
我的服务器应用程序发送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);