【问题标题】:how could we increase the performance of a udp receiver我们如何提高 udp 接收器的性能
【发布时间】:2018-09-29 12:11:50
【问题描述】:

谁能帮助我提高 udp 接收器的性能。我只能获得 1Mb/s,但需要将性能提高到几乎 5Mb/s。也缺少日志,因为接收者由于性能较低而无法接收所有消息。有没有关于我们如何提高性能的提示。我正在使用套接字调用来获取数据包。

#define MAX_PACKET_SIZE 65535
#define UPD_DATAGRAM_BUFFER_SIZE 1536
m_nSocket = socket(AF_INET, SOCK_DGRAM, 0);
/* Set socket buffer size */
    int buffer_size = m_nBufferSize;
    ret = setsockopt(m_nSocket, SOL_SOCKET, SO_RCVBUF, (char*) &buffer_size, sizeof(buffer_size));
    ret = setsockopt(m_nSocket6, SOL_SOCKET, SO_RCVBUF, (char*) &buffer_size, sizeof(buffer_size));
/* Set socket timeout */
#if defined (WIN32) || defined (WIN64)
    int timeout = m_nTimeout;
    ret = setsockopt(m_nSocket, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
    ret = setsockopt(m_nSocket6, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));
#else
    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = m_nTimeout * 1000; //must be in microseconds
    ret = setsockopt(m_nSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    ret = setsockopt(m_nSocket6, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
#endif
//bind
    m_address.sin_family = AF_INET;
    m_address.sin_addr.s_addr = htonl(INADDR_ANY);
    m_address.sin_port = htons(m_nPort);
    ret = bind(m_nSocket, (struct sockaddr*) &m_address, sizeof(m_address));
//receive data
recvfrom(m_nSocket, m_sBuffer, UPD_DATAGRAM_BUFFER_SIZE, 0, (struct sockaddr*) &m_address, &server_length);

增加缓冲区大小会提高 udp 性能吗?我们还能做些什么来提高 udp 性能?

【问题讨论】:

  • 我们是否需要增加接收缓冲区大小和接收超时值
  • 您当然应该将接收缓冲区的大小设置得尽可能高。接收超时值不影响性能。但是 UDP 数据报丢失可能发生在网络中的任何地方,而不仅仅是在接收方,因为它很慢。注意不要使用 cmets 来改善您的问题。改进你的问题。在问题中。
  • MAX_PACKET_SIZE 是干什么用的?如果它是最大 UDP 有效负载,则它太大了。如果是接收缓冲区大小,它太小了。 m_nBufferSize 的值是多少?
  • 在预处理器条件之前,您似乎缺少很多 #
  • @EJP : MAX_PACKET_SIZE 在以下链接中提到:stackoverflow.com/questions/42609561/udp-maximum-packet-size m_nBufferSize 是我们作为接收器缓冲区大小给出的值。在我们的例子中,我们给出 1,048,576 字节,即 1Mb

标签: c++ performance network-programming udp packet-loss


【解决方案1】:

增加 RCVBUF 大小不会使其更快但更可靠。如果 RCVBUF 已满,则丢弃下一个传入数据包。

详情:

recvfrom() 调用仅接收一个 UDP 数据包,该数据包具有 - 对于 IPv4 - 最大大小为 65535 字节。 UDP 数据包可能会被分割成片段,但这对用户是隐藏的。

如果您的 sendto() 调用发送的字节数多于单个 recvfrom() 接收缓冲区接受的字节数,则剩余数据将被丢弃。

在没有运行 recvfrom() 调用时,SO_RCVBUF 正在接受数据包。如果您调用 recvfrom() ,它会检查 RCVBUF 中的数据包,如果接收缓冲区为空,则只会阻塞并等待新数据包。

如果您有一个发送者发送大量数据,例如在一个 for 循环中,那么如果您的 RCVBUF 不够大并且您的 recvfrom() 调用不够快(即处理数据包时),您可能会丢失一些数据revfrom() 调用之间)。

UDP 不适用于突发传输。它甚至不保证数据包的传递,并且数据包接收顺序可能与发送顺序不同。

也许你应该使用 TCP/IP ?


如果您尝试实现自己的基于 UDP 的流式通信,您可以执行以下操作:

1) 发送最大大小约为 1400 字节的 UDP 数据包。

2) 为您的 UDP 数据包添加一个 32 位或 64 位标头,其中包含该数据包所属的流偏移量(即第一个 1400 字节数据包的流偏移量为 0,第二个数据包的偏移量为 1400,即第三个2800等等)

3) 客户端分配一个足够大的缓冲区来存储整个传输。每个数据包都被复制到该缓冲区中数据包前 32 或 64 位中指定的位置。 (这会对你的数据包进行排序)

4) 服务器仅发送负载 - 例如 - 10 MiB,并且客户端在从 RCVBUF 读取时请求更多数据(使用 recvfrom())。因此服务器不会填充 RCVBUF,接收机器也不会丢弃任何数据包。为了获得最佳性能,客户端应请求下一次加载,同时仍从前一次加载中接收数据。 (这样可以确保接收缓冲区不会溢出)

5) 客户端请求重传任何丢失的数据包(这可以与步骤 4 中的请求相结合)(这样可以确保传输完成并且没有数据包丢失)

为什么只有 1400 字节?因为您不想在高速网络上对数据包进行分段。 (在快速网络上,16 位数据包 ID 可能在重组时间范围内溢出,并且 - 如果校验和匹配或未设置 - 可以重组不同数据包的片段。我花了几个小时才找出原因)

【讨论】:

  • 假设发送方正在以更高的速率(例如5Mb/s)发送数据,而接收方只接收数据包(例如1Mb/s),我应该怎么做才能在5发送方发送的 Mb/s。将 RCVBUF 大小增加到 5 Mb 是否会增加接收端的数据速率
  • 在 recv() 调用中可以提供的最大缓冲区大小是多少?
  • 我不确定函数调用的限制是多少,但是IPv4 UDP数据包的长度字段只有16位,所以使用更大的接收数据包缓冲区没有意义。我从未在 IPv6 上使用过 UDP,但我认为 IPv6 上的最大数据包大小会很大。
  • 如果您想要可靠、快速的通信,您可以使用 TCP/IP 或通过 UDP/IP 实现您自己的安全协议。发送方必须等待客户端确认数据包,客户端必须告诉服务器重新发送丢失/丢弃的数据包,并且客户端必须对数据包进行排序。
猜你喜欢
  • 2012-08-23
  • 1970-01-01
  • 1970-01-01
  • 2014-04-09
  • 2021-09-21
  • 2019-08-11
  • 2010-12-23
  • 1970-01-01
  • 2013-01-24
相关资源
最近更新 更多