如何在 C 中刷新 UDP 套接字的输入缓冲区?

发布于 2024-08-22 09:42:36 字数 2300 浏览 4 评论 0原文

如何在 C 中刷新 UDP 套接字的输入缓冲区(如果存在这样的东西)?

我正在开发嵌入式 Linux 环境并使用 C 创建一些本机应用程序。同一网络上有几台这样的嵌入式机器,当其中一台发生事件时(我们称其为 WHISTLE-BLOWER),WHISTLE-BLOWER 应该向网络广播地址发送网络消息,以便网络上的所有机器都收到通知。网络(包括举报人)了解该事件并根据该事件执行一些操作。 顺便说一句,我正在使用 UDP 套接字...

这是它的伪代码:

main
{
    startNetworkListenerThread( networkListenerFunction );

    while( not received any SIGTERM or such )
    {
        localEventInfo = checkIfTheLocalEventOccured();
        broadcastOnNetwork( localEventInfo );
    }
}

networkListenerFunction
{
    bindSocket;

    while( not SIGTERM )
    {
// THIS IS WHERE I WANT TO FLUSH THE RECV BUFFER...
        recv_data = recvfrom( socket );
        if( validate recv data )
        {
            startExecuteLocalAction;
            sleep( 5 );
            stopExecuteLocalAction;
        }
    }
}

期望并想要使用此代码的方式是:

1. LOCAL_EVENT occured
2. Broadcasted LOCAL_EVENT_INFO on network
3. All machines received EVENT_INFO, including the original broadcaster
4. All machines started executing the local action, including the original broadcaster
5. All machines' network listener(thread)s are sleeping
6. Another LOCAL_EVENT2 occured
7. Since all machines' listener are sleeping, LOCAL_EVENT2 is ignored
8. All machines' network listener(thread)s are now active again
9. GO BACK TO 1 / RESTART CYCLE
RESULT = TOTAL 2 EVENTS, 1 IGNORED

它实际的方式工作原理是:

1. LOCAL_EVENT occured
2. Broadcasted LOCAL_EVENT_INFO on network
3. All machines received EVENT_INFO, including the original broadcaster
4. All machines started executing the local action, including the original broadcaster
5. All machines' network listener(thread)s are sleeping
6. Another LOCAL_EVENT2 occured
7. Eventhough all machines' listener are sleeping; LOCAL_EVENT2 is queued  SOMEHOW
8. All machines' network listener(thread)s are now active again
9. All machines received EVENT_INFO2 and executed local actions again, slept and reactivated
10. GO BACK TO 1 / RESTART CYCLE
RESULT = TOTAL 2 EVENTS, 0 IGNORED

tl,dr:发送到已绑定套接字的数据包/消息/UDP 广播,其父线程在传递时刻处于休眠状态;以某种方式排队/缓冲并在所述套接字上的下一个“recvfrom”调用时传递。

我希望忽略这些 UDP 广播,因此我正在考虑刷新接收缓冲区(显然不是我给出的缓冲区) recvfrom 方法的参数)(如果在调用 recvfrom 之前存在)。我怎样才能做到这一点?或者我应该走什么路?

How to flush Input Buffer (if such thing exists at all) of an UDP Socket in C ?

I'm working on an embedded Linux environment and using C to create some native application. There are several of these embedded machines on the same network, and when an event occurs on one of them (lets call it the WHISTLE-BLOWER), WHISTLE-BLOWER should send a network message to the network broadcast address, so that all machines on the network (including the WHISTLE-BLOWER) knows about the event and executes some actions according to it. I'm using UDP socket by the way...

Here's the pseudo-code for it:

main
{
    startNetworkListenerThread( networkListenerFunction );

    while( not received any SIGTERM or such )
    {
        localEventInfo = checkIfTheLocalEventOccured();
        broadcastOnNetwork( localEventInfo );
    }
}

networkListenerFunction
{
    bindSocket;

    while( not SIGTERM )
    {
// THIS IS WHERE I WANT TO FLUSH THE RECV BUFFER...
        recv_data = recvfrom( socket );
        if( validate recv data )
        {
            startExecuteLocalAction;
            sleep( 5 );
            stopExecuteLocalAction;
        }
    }
}

The way I expect and want to work this code is:

1. LOCAL_EVENT occured
2. Broadcasted LOCAL_EVENT_INFO on network
3. All machines received EVENT_INFO, including the original broadcaster
4. All machines started executing the local action, including the original broadcaster
5. All machines' network listener(thread)s are sleeping
6. Another LOCAL_EVENT2 occured
7. Since all machines' listener are sleeping, LOCAL_EVENT2 is ignored
8. All machines' network listener(thread)s are now active again
9. GO BACK TO 1 / RESTART CYCLE
RESULT = TOTAL 2 EVENTS, 1 IGNORED

The way it actually works is:

1. LOCAL_EVENT occured
2. Broadcasted LOCAL_EVENT_INFO on network
3. All machines received EVENT_INFO, including the original broadcaster
4. All machines started executing the local action, including the original broadcaster
5. All machines' network listener(thread)s are sleeping
6. Another LOCAL_EVENT2 occured
7. Eventhough all machines' listener are sleeping; LOCAL_EVENT2 is queued  SOMEHOW
8. All machines' network listener(thread)s are now active again
9. All machines received EVENT_INFO2 and executed local actions again, slept and reactivated
10. GO BACK TO 1 / RESTART CYCLE
RESULT = TOTAL 2 EVENTS, 0 IGNORED

tl,dr: The packets/messages/UDP Broadcasts sent to an already binded socket, whoose parent thread is sleeping at the delivery-moment; are somehow queued/buffered and delivered at the next 'recvfrom' call on the said socket.

I want those UDP broadcasts to be ignored so I was thinking of flushing the receive buffer (obviously not the one i'm giving as parameter to the recvfrom method) if it exists before calling recvfrom. How can I do that? or what path should I follow?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

各空 2024-08-29 09:42:36

请注意,“刷新”的概念仅适用于输出。刷新会清空缓冲区并确保其中的所有内容都已发送到目的地。对于输入缓冲区,数据已经到达目的地。输入缓冲区可以读取或清除,但不能“刷新”。

如果您只想确保已读取输入缓冲区中的所有内容,那么您需要的是非阻塞读取操作。如果您尝试但没有输入,它应该返回错误。

Please note that the notion of "flushing" only applies to output. A flush empties the buffer and ensures everything in it was sent to its destination. Regarding an input buffer, the data is already at its destination. Input buffers can be read from or cleared out, but not "flushed".

If you just want to make sure you have read everything in the input buffer, what you are looking for is a non-blocking read operation. If you try it and there's no input, it should return an error.

人间☆小暴躁 2024-08-29 09:42:36

套接字在 TCP/IP 堆栈内有一个接收缓冲区。它本质上是接收到的数据报的 FIFO。不过,TCP 和 UDP 处理该队列的方式不同。当您在 UDP 套接字上调用 recv(2) 时,您将从该缓冲区中出队单个数据报。 TCP 根据序列号将数据报排列成字节流。当接收缓冲区溢出时,数据报会被堆栈丢弃。在这种情况下,TCP 会尝试重新发送。 UDP 则不然。除了读取套接字或关闭它之外,接收缓冲区没有显式的“刷新”功能。

编辑:

您的应用程序中存在固有的竞争条件,并且看起来您正在尝试使用错误的工具(TCP/IP 堆栈)来解决它。我认为您应该做的是为应用程序定义一个干净的状态机。处理在当前状态下有意义的事件,忽略没有意义的事件。

另一件需要注意的事情是使用多播而不是广播。它涉及更多一些,但您可以通过加入/离开多播组来更好地控制“订阅”。

A socket has a single receive buffer inside the TCP/IP stack. It's essentially a FIFO of the datagrams received. TCP and UDP handle that queue differently though. When you call recv(2) on a UDP socket you dequeue a single datagram from that buffer. TCP arranges the datagrams into a stream of bytes according to the sequence numbers. When receive buffer overflows the datagram is dropped by the stack. TCP tries to resend in this case. UDP doesn't. There's no explicit "flush" function for the receive buffer other then reading the socket or closing it.

Edit:

You have an inherent race condition in your application and it looks like you are trying to solve it with a wrong tool (TCP/IP stack). What I think you should be doing is defining a clean state machine for the app. Handle the events that make sense at current state, ignore events that don't.

One other thing to look at is using multicast instead of broadcast. It's a bit more involved but you would have more control of the "subscriptions" by joining/leaving multicast groups.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文