c-广播UDP套接字中的数据累积(FIFO?)



我有一个设备,它每秒向我发送一个监控数据流(大小为58(,用于广播。我正在用C程序阅读这个流。我的问题是,如果我有几秒钟不读这个流,下次读的时候,我会得到更多我需要的数据,就像我有一个FIFO,在我不读流的时候不断填充一样。

我尝试了使用不同的阅读方法,比如使用select、非阻塞套接字。。。总是一样。也许我只是错过了一个细节。。。下面是一个示例代码:

#include <stdio.h>      /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), sendto(), and recvfrom() */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */
#include <stdlib.h>     /* for atoi() and exit() */
#include <string.h>     /* for memset() */
#include <unistd.h>     /* for close() */
#define MAXRECVSTRING 58  /* Longest string to receive */

int main(int argc, char *argv[])
{
int sock;                         /* Socket */
struct sockaddr_in broadcastAddr; /* Broadcast Address */
unsigned short broadcastPort;     /* Port */
char recvString[MAXRECVSTRING+1]; /* Buffer for received string */
int recvStringLen;                /* Length of received string */
if (argc != 2)    /* Test for correct number of arguments */
{
fprintf(stderr,"Usage: %s <Broadcast Port>n", argv[0]);
exit(1);
}
broadcastPort = atoi(argv[1]);   /* First arg: broadcast port */
/* Create a best-effort datagram socket using UDP */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
perror("socket() failed");
/* Construct bind structure */
memset(&broadcastAddr, 0, sizeof(broadcastAddr));   /* Zero out structure */
broadcastAddr.sin_family = AF_INET;                 /* Internet address family */
broadcastAddr.sin_addr.s_addr = htonl(INADDR_ANY);  /* Any incoming interface */
broadcastAddr.sin_port = htons(broadcastPort);      /* Broadcast port */
/* Bind to the broadcast port */
if (bind(sock, (struct sockaddr *) &broadcastAddr, sizeof(broadcastAddr)) < 0)
perror("bind() failed");
/* Receive datagram from the server */
int g=0;
int time_to_sleep=10; 
while(1)
{
if(g==10)
{
while(time_to_sleep)
{
printf("sleep for %dn", time_to_sleep);
time_to_sleep=sleep(time_to_sleep);
}//after that my next read is 10 data stream of 58 in one !!
}

if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
{
perror("recvfrom() failed");
}
//later will check the header but for now just the size is enough
if (recvStringLen==58){ printf("Read okay bc Size = %d n", recvStringLen); }

}
close(sock);
exit(0);
}

因此,我将尝试解释我的问题:我的设备每秒钟发送一次UDP数据包(大小58(,我不断地读取。在x次(g==10(之后,我决定在10秒内睡觉。在这10秒内,我的设备一直在发送UDP数据包,但我不读也不想读。在第11秒,当我醒来时,我想读我的(g==10(+第11个数据包,而不是第11个+我睡觉时没有读的10个数据包。不幸的是,当我用一个recvfrom阅读第11篇时,我得到了之前的10篇。。。

我试过使用和不使用以太网交换机,以防出现同样的问题。我一定误解了插座里的东西。。。你能帮我吗?

顺便说一下,我的代码可能纯粹是灾难,我是个初学者。不要犹豫,纠正我!

谢谢!

我一定误解了套接字中的某些内容。。。你能帮我吗?

内核中有接收和发送套接字缓冲区。内核接收侦听套接字的数据报,并将它们存储在内核套接字接收缓冲区中。recvfrom调用将内核套接字缓冲区中最旧的数据报复制到用户空间缓冲区中。不调用recvfrom并不意味着内核停止接收数据报(您需要关闭内核的套接字才能停止接收数据(。

您实际上并没有从单个recvfrom中获得10或11个数据包。您在循环中调用recvfrom,循环的每次迭代都读取一个数据包。因此,你需要某种方式来知道你读到的最新数据包是"最后一个"。

做到这一点的方法是不断地阅读,直到没有什么可读的,然后你知道最近的是最后一个。然而,按照当前编写代码的方式,如果没有要读取的数据包,则recvfrom将阻塞,直到数据包可用。您可以通过将套接字置于非阻塞模式来改变这一点:

int fd_flag;
if ((fdflag = fcntl(sock, F_GETFL)) == -1) {
perror("Error getting socket descriptor flags");
exit(1);
}
fdflag |= O_NONBLOCK;
if (fcntl(sock, F_SETFL, fdflag) == -1) {
perror("Error setting non-blocking option");
exit(1); 
}

现在,当您调用recvfrom时,如果没有可用的数据,它将返回-1并将errno设置为EAGAIN。您可以使用它来检查"最后一个"数据包:

while(1)
{
while(time_to_sleep)
{
printf("sleep for %dn", time_to_sleep);
time_to_sleep=sleep(time_to_sleep);
}//after that my next read is 10 data stream of 58 in one !!
int read_one = 0;
while (1) {
if ((recvStringLen = recvfrom(sock, recvString, MAXRECVSTRING, 0, NULL, 0)) < 0)
{
if (errno == EAGAIN) {
// nothing more to read
break;
} else {
perror("recvfrom() failed");
}
} else {
read_one = 1;
if (recvStringLen==58){ printf("Read okay bc Size = %d n", recvStringLen); }
}
}
if (read_one) {
// process last packet read
} else {
// nothing read, so do nothing
}
}

最新更新