c - 如何修复recv将多个TCP段合并为一个?
问题描述
我有两个同伴:Alice 和 Bob。Bob 正试图向 Alice 发送他已知的对等点列表。
首先,Bob 告诉 Alice 他有多少对等点,然后他向n
Alice 发送包含对等点信息的字符串。
这是鲍勃的代码:
if ((send(socket_fd, &(int){ 1 }, sizeof(int), 0)) == -1) { perror("Failed to send"); }
sleep(1); // Give him time to process the rqst
send(socket_fd, &peer_cnt, sizeof(peer_cnt), 0);
for (int i = 0; i < peer_cnt; ++i) {
char *peer_str = get_string(&peers[i]);
printf("Send peer\t:\t%s\n", peer_str);
send(socket_fd, peer_str, strlen(peer_str), 0);
free(peer_str);
}
这是爱丽丝的代码:
char buf[128] = { 0 };
int n = 0;
recv(peer_sock_fd, &n, sizeof(n), 0);
printf("Number of incoming peers:\t%d\n", n);
for (int i = 0; i < n; ++i) {
memset(buf, '\0', sizeof(buf));
recv(peer_sock_fd, buf, sizeof(buf), 0);
puts(buf);
}
例子。如果 Bob 发送 Alice2
字符串,那么存在两种情况。首先,Alice 分别获取它们(如我所愿),例如 Alice 的输出在这种情况下可能是george:127.0.0.1:5555:
和michael:127.0.0.1:4444:
。其次,Alice 将它们作为单个字符串获取,就像这样george:127.0.0.1:5555:michael:127.0.0.1:4444:
为什么有时会合并传入的字符串?
解决方案
TCP 是一种流式协议,当您调用 send() 时,它会将您的消息一个接一个地放入一个特殊的缓冲区,然后发送它们。由于您在很短的时间内调用了多个 send() 系统调用,因此它们中的很多都被放入同一个缓冲区并作为一条消息发送。有时它们会被单独发送,有时它们会被合并,有时只会发送半条消息,这是流协议的默认行为。您应该做的(这就是每个体面的 TCP 程序的实现方式)是分隔您的消息。最好的方法是将消息大小整数作为每条消息的前 4 个字节,然后根据它们的大小分隔消息。我建议您阅读 Beej 关于套接字的指南(https://beej.us/guide/bgnet/html/multi/index.html) 它解释了这个概念等等。非常适合初学者
推荐阅读
- wordpress - Google Compute Engine 中的 Wordpress 网站突然无法访问
- fft - Healpix / Healpy:我如何使用 healpy 对天空进行 SHT 处理?
- c - 我正在用 c 制作井字游戏,wincheck 功能但在下面的代码中不起作用
- vue.js - Vue 应用程序在浏览器中运行通过 CURL 抛出“Javascript not enabled”
- php - laravel/ui[v3.0.0, ..., v3.2.0] 需要照明/控制台 ^8.0 -> 找到照明/控制台[v8.0.0, ..., v8.36.2]
- dictionary - 使用一组数组作为键和值在 julia 中创建字典?
- python - 如何从列表项中删除“\n”
- go - 如何获取给定 k8s 资源的 json 的 schema.GroupVersionResource
- bash - 需要帮助使用空白行 (BASH) 拆分文件
- javascript - 在 TypeScript 中递归地进行树遍历的异步/等待