-2

I have two peers: Alice and Bob. Bob is trying to send Alice the list of peers known to him.

First, Bob tells Alice how many peers he has, then he sends n strings with the information about peers to Alice.

Here's the code for Bob:

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);
}   

Here's the code for Alice:

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);
}

Example. If Bob sends Alice 2 strings, then there are two cases exist. First, Alice gets them separately (as it's intended by me), e.g. Alice's output might be in this case george:127.0.0.1:5555: and michael:127.0.0.1:4444:. Second, Alice gets them as single string, like this george:127.0.0.1:5555:michael:127.0.0.1:4444:

Why are incoming strings merged sometimes?

Radical Ed
  • 178
  • 2
  • 13
  • 6
    TCP is a streaming protocol, so there are no message boundaries. You need to take care of delineating your data and not assume that you get the data grouped in the same way it was sent. Even your first read to read the `int` you should be checking that you have received 4 bytes before assuming you have a valid int. Then you should have some form of delimiter between each string so you can determine the end of the string. – Chris Taylor Mar 24 '19 at 13:59
  • You can't 'fix' it because it isn't broken, and it isn't just due to `recv()`, it happens at both the sender and the receiver. – user207421 Mar 24 '19 at 15:52

1 Answers1

2

TCP is a streaming protocol and when you call send() it puts your messages into a special buffer one after the other and then sends them. Since you are calling multiple send() syscalls in a very short time-frame a lot of them get put in the same buffer and get sent as one single message. Sometimes they will get sent separately and sometimes they will be merged, sometimes there will be just half a message sent, default behavior of streaming protocols. What you should do (and that's how every decent TCP program is implemented) is delimit your messages. Best way is to have a message size integer as the first 4 bytes of every message and then separate messages according to their sizes. I recommend you read Beej's guide on sockets (https://beej.us/guide/bgnet/html/multi/index.html) It explains this concept and much more. Very beginner friendly