我正在开发一个客户端/服务器应用程序。客户端和服务器在运行Ubuntu 16.04的两台不同计算机上运行。客户端发送两个影响服务器部分流量的变量,因此,我希望尽可能地降低丢包率。我的应用程序是基于线程的。
在一个线程中UDP服务器正在运行。我的项目有一个使用Qt实现的GUI。当我尝试实现UDP服务器阻塞时,整个程序和GUI冻结,直到收到数据包。有时即使收到数据包,程序也没有响应。
因此,我认为非阻塞UDP是最好的方法。我设法使用select()使UDP无阻塞。现在出现了问题。如果我将recvfrom
的超时设置为10毫秒并允许线程每10毫秒运行一次,几乎没有数据包丢失,但显然,UDP线程消耗程序冻结的所有处理器时间。如果我增加了调用线程的间隔或减少了超时间隔,则大约80%的数据包会丢失。我知道UDP是无连接协议,TCP可能是更好的选择,但我必须使用UDP
,因为客户端通过UDP发送数据包。
问题是:如何在不阻止其他线程高效执行的情况下降低丢包率?
以下是我的代码(基于Stackoverflow的答案,目前我找不到这里的引用)。
void receiveUDP(void)
{
fd_set readfds;
static int fd;
static struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 10000;
static char buffer[10];
static int length;
if ( (fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("socket failed");
return;
}
struct sockaddr_in serveraddr;
memset( &serveraddr, 0, sizeof(serveraddr) );
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons( 50037 );
serveraddr.sin_addr.s_addr = htonl( INADDR_ANY );
if( bind(fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0)
{
perror("bind failed");
return;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
int rv = select(fd+1, &readfds, NULL, NULL, &tv);
if(rv == -1)
{
printf("Error in Select\n");
_exit(0);
}
else if(rv == 0)
{
printf("Timeout\n");
}
else
{
if(FD_ISSET(fd, &readfds))
{
length = recvfrom(fd, buffer, sizeof(buffer) - 1, 0, NULL, 0);
if(length < 0)
{
perror("recvfrom failed");
}
else
{
printf("%d bytes received: \n", length);
}
}
}
close(fd);
}