C语言 如何在 C 中刷新 UDP 套接字的输入缓冲区?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2299894/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to flush Input Buffer of an UDP Socket in C?
提问by Cihan Keser
How to flush Input Buffer (if such thing exists at all) of an UDP Socket in C ?
如何在 C 中刷新 UDP 套接字的输入缓冲区(如果存在这种情况)?
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...
我正在嵌入式 Linux 环境中工作,并使用 C 来创建一些本机应用程序。在同一个网络上有几台这样的嵌入式机器,当其中一台发生事件时(我们称之为吹哨人),吹哨人应该向网络广播地址发送网络消息,以便所有机器在网络(包括 WHISTLE-BLOWER)知道该事件并根据它执行一些操作。顺便说一下,我正在使用UDP套接字...
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 wantto 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.
tl,dr:发送到已绑定套接字的数据包/消息/UDP 广播,其父线程在交付时刻处于休眠状态;以某种方式排队/缓冲并在所述套接字上的下一个“recvfrom”调用中传递。
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?
我希望这些 UDP 广播被忽略,所以我想刷新接收缓冲区(显然不是我作为参数提供给 recvfrom 方法的那个),如果它在调用 recvfrom 之前存在。我怎样才能做到这一点?或者我应该遵循什么路径?
回答by bta
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.
如果您只想确保已读取输入缓冲区中的所有内容,那么您正在寻找的是非阻塞读取操作。如果你尝试它并且没有输入,它应该返回一个错误。
回答by Nikolai Fetissov
A socket has a single receive bufferinside 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 dequeuea 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.
套接字在 TCP/IP 堆栈内有一个接收缓冲区。它本质上是接收到的数据报的 FIFO。但是,TCP 和 UDP 处理该队列的方式不同。当您调用recv(2)UDP 套接字时,您将从该缓冲区中取出单个数据报。TCP 根据序列号将数据报排列成字节流。当接收缓冲区溢出时,数据报被堆栈丢弃。在这种情况下,TCP 会尝试重新发送。UDP 没有。除了读取套接字或关闭它之外,接收缓冲区没有明确的“刷新”功能。
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 thinkyou 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.
您的应用程序中存在固有的竞争条件,看起来您正试图使用错误的工具(TCP/IP 堆栈)解决它。是什么,我认为你应该做的是定义一个干净的状态机的应用。处理在当前状态下有意义的事件,忽略没有意义的事件。
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.
要考虑的另一件事是使用多播而不是广播。这有点复杂,但您可以通过加入/离开多播组来更多地控制“订阅”。

