【问题标题】:UDP Server Socket Buffer OverflowUDP 服务器套接字缓冲区溢出
【发布时间】:2012-07-12 03:49:42
【问题描述】:

我正在 Linux 上编写 C++ 应用程序。我的应用程序有一个 UDP 服务器,它在某些事件上向客户端发送数据。 UDP 服务器还会收到来自客户端的一些反馈/确认。

为了实现这个应用程序,我使用了一个 UDP 套接字(例如 int fdSocket)来发送和接收来自所有客户端的数据。我将这个 socked 绑定到端口 8080 并将套接字设置为 NON_BLOCKING 模式。

我创建了两个线程。在一个线程中,我等待某个事件发生,如果发生事件,则使用 fdsocket 将数据发送到所有客户端(在 for 循环中)。

在另一个线程中,我使用fdSocket 从客户端(recvfrom())接收数据。该线程计划每 4 秒运行一次(即每 4 秒它将调用 recvfrom() 以从套接字缓冲区检索数据。由于它处于非阻塞模式,如果没有 UDP 数据,recvfrom() 函数将立即返回可用,然后我会去睡觉 4 秒)。

来自所有客户端的 UDP 反馈/确认有一个固定的有效负载,大小为 20 字节。

现在我有两个与此实现相关的问题:

  1. 使用同一个socket发送/接收UDP数据是否正确 有多个客户?
  2. 如何找到我的应用程序在没有 UDP 套接字缓冲区溢出的情况下可以处理的最大 UDP 反馈/确认数据包数(因为我每 4 秒读取一次,如果我 在这 4 秒内收到很多数据包我可能会丢失一些数据包,即,我需要找到可以安全处理的数据包/秒速率)?

我尝试使用函数调用 getsockopt(fdsocket,SOL_SOCKET,SO_RCVBUF,(void *)&n, &m); 获取我的套接字 (fdsocket) 的 Linux 套接字缓冲区大小。从这个函数中,我发现我的套接字缓冲区大小为 110592。但我不清楚这个套接字缓冲区中将存储哪些数据:它是否只存储 UDP 有效负载或整个 UDP 数据包或事件整个以太网数据包?我参考了这个link 来获得一些想法,但很困惑。

目前我的代码有点脏,我会尽快清理并在这里发布。

以下是我在发布此问题之前参考的链接。

  1. Linux Networking
  2. UDP SentTo and Recvfrom Max Buffer Size
  3. UDP Socket Buffer Overflow Detection
  4. UDP broadcast and unicast through the same socket?
  5. Sending from the same UDP socket in multiple threads
  6. How to flush Input Buffer of an UDP Socket in C?
  7. How to find the socket buffer size of linux
  8. How do I get amount of queued data for UDP socket?

【问题讨论】:

  • 为什么只有每 4 秒?为什么不让该线程坐在select() 呼叫中等待数据?
  • @Collin 由于 UDP 不可靠,我们实现了以下机制。对于发送到客户端的每个 UDP 数据包,我都希望从客户端返回一个确认数据包(带有固定字符串的简单 UDP 数据包。)。如果我没有收到来自客户端的确认数据包,那么我将在 4 秒后再次发送数据包
  • 好的,但是通过这种设置,服务器会认为数据包丢失了,即使它们没有丢失。在客户端读取套接字之后发送数据包会发生什么?使用网络计时,即使有响应,服务器也会认为从来没有响应。仍然没有理由不立即回应。尽管您可能会考虑使用 TCP 或类似的东西,而不是滚动您自己的可靠性:udt.sourceforge.net
  • 您应该使用 select() 或使用阻塞模式并设置 4 秒 SO_TIMEOUT。这样,如果一个数据包在 4 秒内到达,您将立即读取它,而不是在睡眠中浪费时间。
  • @EJP 。您的评论很棒,它给了我清晰的想法,我会尝试以这种方式实施。我想给你的评论投票,但不幸的是我点击了两次,系统不允许我给你的评论投票:-(

标签: c++ linux sockets udp buffer


【解决方案1】:

你可以看到最大允许的缓冲区大小:

sysctl net.core.rmem_max

您可以通过以下方式设置可以使用的最大缓冲区大小:

sysctl -w net.core.rmem_max=8388608

您还可以通过使用 setsockopt 和更改 SO_RCVBUF 在运行时设置缓冲区大小(不超过上述最大值)。您可以通过查看 /proc/net/udp 查看缓冲区级别。

缓冲区用于存放UDP头和应用数据,其余属于低层。

【讨论】:

    【解决方案2】:

    以四秒的固定间隔读取套接字肯定会让您丢失数据包。非阻塞 I/O 的传统可靠方法是解复用器系统调用select(2)/poll(2)/epoll(7)。看看你是否可以使用这些来捕捉/响应你的其他事件。

    另一方面,由于您已经在使用线程,您可以直接阻塞 recv(2) 而无需四秒钟的睡眠。

    阅读Stevens了解SO_RCVBUF的解释。

    【讨论】:

    • 连同EJP发表的评论给出了一个清晰的想法。
    【解决方案3】:

    问:使用同一个套接字与多个客户端发送/接收 UDP 数据是否正确?

    A:是的,没错。

    问:如何找到我的应用程序在没有 UDP 套接字缓冲区溢出的情况下可以处理的最大 UDP 反馈/确认数据包数(因为我每 4 秒读取一次,如果我在这 4 秒内收到很多数据包,我可能会丢失一些数据包,即.,我需要找到可以安全处理的速率:noofpackets/sec)?

    答:瓶颈可能是网络带宽、CPU 或内存。您可以简单地做一个测试,使用客户端向服务器发送连续编号的ACK,并验证服务器是否存在丢包。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-02
      • 2014-08-17
      • 2021-06-11
      • 1970-01-01
      相关资源
      最近更新 更多