在C中处理丢包UDP套接字编程

时间:2013-01-18 12:29:52

标签: c sockets udp

我想发送一个字节数组X次,直到达到缓冲区大小。我的客户端发送字节数组,直到缓冲区大小已满。但问题是数据包丢失,服务器只收到8/10的缓冲区大小。

客户端:

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

服务器:

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

我无法真正想出这个问题的解决方案。当客户端发送了所有软件包,并且服务器遭受软件包丢失时,while循环将不会结束,有什么想法我可以解决这个问题吗?

非常感谢

4 个答案:

答案 0 :(得分:2)

哼。您正在使用UDP。对于这个协议,如果有需要,它可以丢弃数据包。因此,就“发送的内容将会到达”而言,这是不可靠的。您在客户端需要做的就是检查所有需要到达的数据包,如果没有,请礼貌地与您的服务器交谈以重新发送您未收到的数据包。要实现这些东西并不是那么容易,你最终可能会得到一个解决方案,而不仅仅是使用普通的旧tcp-socket,因此我的推荐将是第一个切换到tcp连接的实例。

答案 1 :(得分:2)

如果您必须使用UDP传输大量数据,那么设计一个小的应用程序级协议,以处理可能的数据包丢失和重新排序(这是TCP为你做的一部分)。我会选择这样的东西:

  • 数据报小于 MTU (加上IP和UDP标头)的大小(比如1024字节),以避免IP碎片。
  • 每个数据报的固定长度标头,包括数据长度序列号,因此您可以将数据拼接在一起,并检测遗漏,重复和重新订购部件。
  • 致谢从收件人那里成功收到并放在一起。
  • 当这些ack没有在适当的时间内到达时,发送方
  • 超时重新传输

你走了。我们又开始构建TCP ......

答案 2 :(得分:0)

当然TCP是更好的选择,但如果你只有UDP选项,我将数据包装到一个带有sequence和buf_length字段的结构中。

它绝对不是最佳解决方案......它只是处理序列号,以确保数据完全到达并具有正确的顺序。如果没有,只需停止接收数据(它可以做一些更聪明的事情,比如要求发送重新发送片段并重建数据,尽管顺序错误但它会变得非常复杂)

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

发送方:

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

接收方:

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

答案 3 :(得分:0)

发送后你可以等待sendto缓冲区达到零,你可以在每次sendto调用后使用以下api。

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