如何解决将多个TCP段合并为一个的recv?

时间:2019-03-24 13:49:05

标签: c sockets tcp recv

我有两个同龄人:爱丽丝和鲍勃。鲍勃(Bob)试图向爱丽丝发送他认识的同伴列表。

首先,鲍勃(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发送Alice 2字符串,则存在两种情况。 首先,爱丽丝将它们分开(按照我的意愿),例如在这种情况下,Alice的输出可能为george:127.0.0.1:5555:michael:127.0.0.1:4444:。 其次,爱丽丝将它们作为单个字符串获取,例如george:127.0.0.1:5555:michael:127.0.0.1:4444:

为什么有时传入的字符串会合并?

1 个答案:

答案 0 :(得分:2)

TCP是一种流协议,当您调用send()时,它将消息一个接一个地放入一个特殊的缓冲区中,然后发送它们。由于您要在很短的时间内调用多个send()系统调用,因此许多调用会被放入同一缓冲区中并作为一条消息发送。有时它们将分别发送,有时将被合并,有时仅发送一半的消息,这是流协议的默认行为。您应该做的(这就是实现每个体面的TCP程序的方式)来分隔消息。最好的方法是将消息大小的整数作为每个消息的前4个字节,然后根据消息的大小将它们分开。我建议您阅读Beej的套接字指南(https://beej.us/guide/bgnet/html/multi/index.html),它解释了此概念以及更多内容。非常适合初学者