我正在编写一个客户端程序,它将流UDP数据包发送到服务器。在服务器中,每当收到UDP数据包时,它应该进行一些处理并将数据包发送回客户端。
对于这种情况,我是否必须在服务器中实现一个队列来处理UDP数据包流或底层协议层处理这个?
换句话说,如果服务器使用recvfrom()
API等待UDP数据包,只要它收到UDP数据包,处理它并再次使用recvfrom()
等待下一个UDP数据包就足够了API。
答案 0 :(得分:1)
UDP没有内置流量控制。这意味着除非服务器不能保证比客户端发送数据报录更快地处理数据报,否则最终会有一个完整的接收缓冲区,网络堆栈将丢弃传入的数据包。这与设置较大的缓冲区大小无关(只会延迟问题,但不会修复它)。
因此,如果您确切地知道发送数据包的速率,比如说每秒50左右,则服务器可以轻松应对(在最差< / em> case,不是最好的情况!),你很擅长一个简单的阻止recvfrom
。
否则,除非丢失大量数据包是非问题,否则您需要实现某种类似于TCP正在进行的流控制方式。例如:允许客户端发送最多20个数据包,每收到一个应答数据包加一个数据包,这是一种非常简单的算法。
另一个(明显的)解决方案是卸载处理并向某些工作线程发送答案,但是就像增加缓冲区大小一样,这只会使问题向后移动一点,但它不能解决问题。此外,服务器设计要复杂得多 尽管如此,如果客户端可以以几乎无限的速度发送数据(例如,10G上每秒12-14万个数据包),那么如果工作线程无法处理该卷,它最终将超过您的处理能力。
答案 1 :(得分:0)
我认为你不需要处理服务器端的UDP数据包,底层网络协议(大多数协议都是这样做但你不依赖它)做你的工作。
现在关于在服务器端等待UDP数据包,你可以使用非阻塞套接字连接,所以每次你轮询该函数(或放入while(1)
循环)接受客户端请求,如果客户端连接然后只是接收来自它的数据包。如果您调用该功能,则下次检查客户端是否已连接,如果是,则只需从该连接接收UDP数据。
让我解释一下如何在服务器端接收数据包:
假设函数acceptUDPPaket()
为您起作用
int accept_sock[5];
int serversock;//listen on this server socket
void acceptUDPPaket(void)
{
struct sockaddr client;
int clientsize;
char i;
int sock;
clientsize = sizeof(struct sockaddr_in);
for(i=0;i<5;i++) // I have take maximum 5 client connection
{
if(accept_sock[i] == SYS_SOCKETNULL)
{
//your accept socket code
//ex:
sock=accept(serversock, &client, &clientsize);
if(sock != NULL)
{
accept_sock[i] =sock;
break;
}
}
}
for(i=0;i<5;i++)
{
if(accept_sock[i] != NULL)
{
receveFrom(&accept_sock[i]);//receive UDP packet from client and process on it
}
}
}
因此,伪代码可能会清除您的混淆。
答案 2 :(得分:0)
Linux TCP / IP堆栈肯定有一个UDP数据包缓冲区,其大小可通过sysctl -w net.core.rmem_max=
等进行调整。
防止服务器上的UDP数据包丢失的最快方法是将最大大小和长度增加到非常大的值,如果它对您和服务器管理员来说是可接受的。
带有阻塞套接字的 recvfrom()
完全可以。