views:

1023

answers:

7

I'm writing a C/C++ application under Linux that reads data from a raw socket (for ICMP packets). Question: is there a way to discard all data that is still queued on the socket?

The problem is that after sleeping for a while, there is data queued up on the socket which I'm not interested in; so it would be best to just tell the socket "forget all data you have buffered right now", so that if I go into a select()/recvfrom() loop then, I only get data that was received recently.

Is there a better way than going into a separate poll()/recvfrom() loop first? Some socket API call maybe? Portable, even? :-)

+1  A: 

The only way I know how to do it reliably is to close the socket.

Ichorus
Quite possibly the best solution in this case - it's simple, at least.
MarkR
A: 

I have not tried it, and it might be totally unwise for performance reasons (but if your app sleeps anyway, it might not be a problem), but: you might try setting the socket's receive buffer to some very small value before the sleep. I'm hoping this will cause the socket to not be able to buffer data that arrives when the application is not listening. It's kind of a long shot.

Alternatively, perhaps resetting the receive buffer size after the sleep, when you're ready to start reading again, causes it to flush it as well. Of course, these kinds of tricks are just that, and even if they work they are most certainly not portable. I just thought I'd share the idea, if you have a chance of testing it it might help you.

unwind
A: 

Can you do something like this, right before you sleep?

for(n=0;n<=MAX_BUFFER_SIZE;n++)
{
recv_buffer[n] = 0;
}
Tim Howland
+1  A: 

Can't you just do a recvfrom() into a temporary buffer and discard the buffer?

Adam Rosenfield
Yes, that's what I ended up to do... Instead of calling sleep(), I use select() with a timeout, and if the select() call indicates incoming data, the data is received with recvfrom() and ignored, and a new select() is made, until the sleep time is over.
oliver
+2  A: 

During idle times, you can disable the socket by setting the Receive Buffer size to zero:

 int optval = 0; /* May need to be 1 on some platforms */

 setsockopt(sockDesc, SOL_SOCKET, SO_RCVBUF, (char *)(&optval), sizeof(optval));

Re-enable by setting "optval" to a larger buffer (e.g. 4096).

JayG
Does this really work? If so, it sounds good.
MarkR
Yes, I use it in VxWorks and eCos. You'll want to make sure your OS supports the flags, but I think it's fairly standard.
JayG
+1  A: 

I would recommend not sleeping at all. Insted using the select call to handle the data right away when it arrives.

while (1) {

FD_ZERO (&sockets);
FD_SET (raw_socket, &sockets);

timeout.tv_sec = 1;
timeout.tv_usec = 0;

if (select (raw_socket + 1, &sockets, NULL, NULL, &timeout))
{
  if (FD_ISSET (raw_socket, &sockets))
  {
     // handle the packet
  }
}
else
{
  /* Select Timed Out */
  fprintf(stderr, "Timed out");
}

}

Also, when creating your raw socket you could specify that you are only interested in icmp packets.

A: 

Standard procedure in middleware applications is to have a dedicated thread to service IO requests with the priority set to higher than the other application threads. When the IO thread receives a packet it enqueues it to the application layer. When the application has free time it dequeues the next packet.

This is the architecture behind TIBCO Rendezvous as used in many real time market data and enterprise messaging systems. The caveat being you generally want some limit on the queue size so the application doesn't get reaped by the OOM manager. The protocol between the IO thread and the application layer can vary from simple asynchronous queue to more complicated subject filtering, priority lists, and support for thread pools to decode the incoming data in parallel.

Steve-o