UDP服务器套接字缓冲区溢出

7
我正在Linux上编写一个C++应用程序。我的应用程序有一个UDP服务器,可以在某些事件发生时向客户端发送数据。UDP服务器还会从客户端接收一些反馈/确认信息。
为了实现这个应用程序,我使用了一个单独的UDP套接字(例如int fdSocket)来向所有客户端发送和接收数据。我将此套接字绑定到端口8080,并将套接字设置为非阻塞模式。
我创建了两个线程。其中一个线程等待某个事件发生,如果发生事件,则使用fdsocket向所有客户端发送数据(在for循环中)。
在另一个线程中,我使用fdSocket从客户端接收数据(recvfrom())。该线程被安排每4秒运行一次(即每4秒它将调用recvfrom()从套接字缓冲区检索数据。由于它处于非阻塞模式,如果没有UDP数据可用,recvfrom()函数将立即返回,然后我将休眠4秒)。
来自所有客户端的UDP反馈/确认具有固定大小的有效负载,其大小为20字节。
现在我有两个与此实现相关的问题:
  1. 使用同一个套接字与多个客户端发送/接收UDP数据是否正确?
  2. 如何找到应用程序可以处理的最大UDP反馈/确认数据包数量,而不会发生UDP套接字缓冲区溢出(因为我每4秒读取一次,如果在这4秒内接收到许多数据包,我可能会丢失一些数据包,即需要找到我可以安全处理的数据包/秒速率)?

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

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

以下是我在发布这个问题之前参考过的链接。
  1. Linux网络编程
  2. UDP发送和接收最大缓冲区大小
  3. 检测UDP套接字缓冲区溢出
  4. 通过同一套接字进行UDP广播和单播?
  5. 在多个线程中从同一UDP套接字发送数据
  6. 如何在C语言中清空UDP套接字的输入缓冲区?
  7. 如何查找linux的套接字缓冲区大小
  8. 如何获取UDP套接字排队数据的数量?

1
为什么只有每4秒钟才会执行一次?为什么不让该线程在select()调用中等待数据呢? - Collin
@Collin,由于UDP不可靠,我们已经实现了以下机制。对于发送到客户端的每个UDP数据包,我都期望从客户端收到一个确认数据包(一个简单的UDP数据包,其中包含一个固定字符串)。如果我没有从客户端收到确认数据包,则会在4秒后再次重发该数据包。 - Dinesh P.R.
1
好的,但是使用这种设置时,即使数据包没有丢失,服务器也会认为数据包已经丢失了。当客户端在读取套接字后立即发送一个数据包时会发生什么?由于网络定时,服务器会认为根本没有响应,即使实际上已经有响应了。虽然还没有理由不立即响应,但你可以考虑使用TCP或类似的东西(例如:http://udt.sourceforge.net/)而不是自己编写可靠性功能。 - Collin
3
你应该使用select()或者使用阻塞模式并设置4秒的SO_TIMEOUT。这样,如果在4秒内收到数据包,你将立即读取它,而不是在等待过程中浪费时间。 - user207421
@EJP。你的评论很棒,给了我清晰的思路,我会尝试按照那种方式实现。我想为你的评论投票,但不幸的是我已经点了两次,系统不允许我投票你的评论 :-( - Dinesh P.R.
3个回答

7

固定间隔四秒进行套接字读取操作会导致数据包丢失。非阻塞I/O的传统做法是使用多路复用系统调用select(2)/poll(2)/epoll(7)。请尝试使用它们来捕获和响应您的其他事件。

另一方面,由于您已经在使用线程,因此可以使用阻塞recv(2)而无需那个四秒的休眠。

阅读SO_RCVBUF的解释,请参考Stevens


除此之外,EJP 发表的评论提供了清晰的想法。 - Dinesh P.R.

5

您可以查看允许的最大缓冲区大小:

sysctl net.core.rmem_max

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

sysctl -w net.core.rmem_max=8388608

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

该缓冲区用于存储UDP标头和应用程序数据,其余部分属于较低级别。


4

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

答:是的,这是正确的。

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接