bungieqdf
bungieqdf

Reputation: 65

Handle packet loss UDP socket programming in C

I want to send a byte array X times until I've reached the buffer size. My client send the byte array until the buffer size is full. But the problem is packet loss and the server only recieves like 8/10 of the buffer size.

Client:

while(writeSize < bufferSize)
{
    bytes_sent += sendto(servSocket, package, sizeof(package), 0, (struct sockaddr *)&server, sizeof(server));
    writeSize+= sizeof(package);    
}

Server:

while(packetSize < bufferSize)
{
    bytes_recv += recvfrom(servSocket, package, sizeof(package), 0, (struct sockaddr*)&client, &size);
    packetSize += sizeof(package);
    printf("Bytes recieved: %d\n", bytes_recv);
}

I can't really come up with a solution with this problem. When the client has sent all the packages, and the server suffers from package loss the while loop won't end, any ideas how I can solve this?

Many thanks

Upvotes: 6

Views: 10164

Answers (4)

devesh
devesh

Reputation: 76

after sendto you can wait for sendto buffer to reach zero, you can use the following api after each sendto call.

void waitForSendBuffer(void)
{
int outstanding = 0;
while(1)
{
  ioctl(socketFd_, SIOCOUTQ, &outstanding);
  if(outstanding == 0)
    break;
  printf("going for sleep\n");
  usleep(1000);
}
}

Upvotes: 0

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84151

If you have to use UDP to transfer a largish chunk of data, then design a small application-level protocol that would handle possible packet loss and re-ordering (that's part of what TCP does for you). I would go with something like this:

  • Datagrams less then MTU (plus IP and UDP headers) in size (say 1024 bytes) to avoid IP fragmentation.
  • Fixed-length header for each datagram that includes data length and a sequence number, so you can stitch data back together, and detect missed, duplicate, and re-ordered parts.
  • Acknowledgements from the receiving side of what has been successfully received and put together.
  • Timeout and retransmission on the sending side when these acks don't come within appropriate time.

Here you go. We started building TCP again ...

Upvotes: 3

Davide Berra
Davide Berra

Reputation: 6568

Of course TCP would be the better choice but if you only have UDP option i'd wrap the data into a structure with sequence and buf_length field.

It is absolutely NOT an optimal solution... It just take care of sequence number in order to assure the data is totally arrived and with the right order. If not, just stop to receive data (It could do something smarter like ask to the send to resend pieces and rebuild the data despite thw wrong order but it will become really complex)

struct udp_pkt_s {
    int     seq;
    size_t  buf_len;
    char    buf[BUFSIZE];
};

sending side:

struct udp_pkt_s udp_pkt;

udp_pkt.seq = 0;

while(writeSize < bufferSize)
{
    // switch to the next package block
    // ...

    memcpy(udp_pkt.buf, package);
    udp_pkt.buf_len = sizeof(package);
    udp_pkt.seq++;

    bytes_sent += sendto(servSocket, &udp_pkt, sizeof(udp_pkt_s), 0, (struct sockaddr *)&server, sizeof(server));
    writeSize += sizeof(package);    
}

receiving side:

last_seq = 0;

while(packetSize < bufferSize)
{
    bytes_recv += recvfrom(servSocket, &udp_pkt, sizeof(udp_pkt_s), 0, (struct sockaddr*)&client, &size);

    // break it if there's a hole
    if (udp_pkt.seq != (last_seq + 1))
        break;

    last_seq = udp_pkt.seq;

    packetSize += udp_pkt.buf_len;

    printf("Bytes recieved: %d\n", udp_pkt.buf_len);
}

Upvotes: 1

pbhd
pbhd

Reputation: 4467

Hmpf. You are using UDP. For this protocol its perfectly ok to throw away packets if there is need to do so. So it's not reliable in terms of "what is sent will arrive". What you have to do in your client is to check wether all packets you need arrived, and if not, talk politely to your server to resend those packets you did not receive. To implement this stuff is not that easy, and you might finally end up with a solution wich might be less performant than just using plain old tcp-sockets, so my recomendation would be in the first instance to switch to a tcp connection.

Upvotes: 3

Related Questions