flushing a socket buffer

S

Stephan Steiner

Hi

I have a networking application that periodically needs to go into sleep
mode (from an application point of view, I'm simply suspending the receiver
thread until it's time to start listening to incoming packets again). The
packets I'm interested in are UDP broadcasts, so they are simply dropped
when nobody application is listening at the specified port. However, when I
initialize my receiver, there's a socket listening at the appropriate port,
so even when I suspend reception of incoming packets, the socket buffer is
still being filled, and only when it's full, will packets be dropped. I'd
like to not have any "old" packets after re-enabling the receiver, so I have
to somehow flush the receive buffer associated to my socket, but I haven't
found any way to do so. Note that I'm not using any streams on top of the
socket (actually I'm not even use a socket directly, I'm using a UDPClient,
but it allows you to retreive the underlying socket so operations on that
level would nevertheless be possible).
Any ideas?

Regards
Stephan Steiner
 
R

Rich Blum

Stephan Steiner said:
However, when I
initialize my receiver, there's a socket listening at the appropriate port,
so even when I suspend reception of incoming packets, the socket buffer is
still being filled, and only when it's full, will packets be dropped. I'd
like to not have any "old" packets after re-enabling the receiver, so I have
to somehow flush the receive buffer associated to my socket, but I haven't
found any way to do so.

Stephan -

You can not flush the socket buffer data without reading what's in
there, but you can prevent datagrams from being stored in the buffer
by reducing the size of the socket buffer.

To accomplish this you need to set the socket receive buffer to 0
before suspending reception of incoming packets. You can use the
SetSocketOption() method to force the receive buffer to 0:

sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 0);

This will prevent additional datagrams from entering the socket
buffer until you are ready to read them (you probably want to set the
buffer back to a reasonable size when you are ready to read again).
Hope this helps solve your problem.

Rich Blum - Author
"C# Network Programming" (Sybex)
http://www.sybex.com/sybexbooks.nsf/Booklist/4176
"Network Performance Open Source Toolkit" (Wiley)
http://www.wiley.com/WileyCDA/WileyTitle/productCd-0471433012.html
 
S

Stephan Steiner

Hi
To accomplish this you need to set the socket receive buffer to 0
before suspending reception of incoming packets. You can use the
SetSocketOption() method to force the receive buffer to 0:

sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 0);

I have already tried that yesterday (I was going through the entire
system.net.socket namespace to try and find a solution), but it didn't work
as it should. I've set the ReceiveBuffer to zero, and I've verified that the
buffer size has indeed by set to zero using
sock.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer), however despite it being zero, when I send
packets while the receiver is inactive, once I activate it again, I still
have 13 of the packets I sent during the inactive period. In fact, if I set
the buffer to zero and leave it like that during the whole program run, I
still receive incoming packets even when the receiver is active. I do no
longer get all of them, but shouldn't I get none if I have a buffer size
that doesn't even allow to store one single of my 750 byte packets (722 byte
payload plus IP and UDP headers)?

Here's the code snippet I'm using:

UdpClient receiver;
IPEndPoint remoteSender;
Byte[] packet;
public Thread thread;
bool listening;
//PacketHandler handler;
Timer tim;
TimerState s;
public int nbPackets;
int seqNo;
Socket sock;

public Receiver(int localPort) : base()
{
receiver = new UdpClient(localPort);
remoteSender = new IPEndPoint(IPAddress.Any,0);
sock = this.Client;
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Broadcast, 1);
int receiveBuffer = (int)sock.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer);
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 0);
int sent = receiver.Send(new byte[2], 2, "192.168.1.255", 14888);
packet = receiver.Receive(ref remoteSender);
//Object o = sock.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.PacketInformation);
//this.handler = handler;
listening = false;
nbPackets = 0;
s = new TimerState();
TimerCallback timerDelegate = new TimerCallback(this.timeToSleep);
tim = new Timer(timerDelegate, null, Timeout.Infinite, Timeout.Infinite);
//
ThreadStart startMethod = new ThreadStart(this.run);
thread = new Thread(startMethod);
thread.Start();
receiveBuffer = (int)sock.GetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer);
thread.Suspend();
}

/**
* method that is running when the thread is active
* receives a packet from the network and processes it
*/
public void run()
{
while (true)
{
packet = receiver.Receive(ref remoteSender);
nbPackets++;
seqNo = BitConverter.ToInt16(packet, 0);
Console.Write(nbPackets.ToString() + ":" + seqNo.ToString() + " / " );
//o.ToString();
// spit out packet for processing handler.processPacket(packet);
}
}

I have a main program that suspends and resumes the thread every 10 seconds.
The timer will shut down the receiver after 5 seconds if nbPackets has not
been received (in other words: when there has been no new packet). I use the
same code to send packets like last time (maybe you remember, I sent you the
code because I was having a problem with UdpClient not receiving all packets
on my machine at work.. ).

Stephan
 
R

Rich Blum

-----Original Message-----
It gets even better.

As a workaround for my problem, I tried to read any pending data from the
socket, before activating the listening thread again. To find out if there's
pending data I used this code:

sock.Poll(10000, SelectMode.SelectRead)

which according to the documentation should return true if there's data to
be read. However, it always returns false. The next line in the program is
already the reactivation of the thread (thread.resume()), and subsequent
calls to receiver.Receive(ref remoteSender) (receiver is a UDPClient) yield
packets that have been sent during the period where the receiver thread was
deactivated. I find this highly confusing because we're talking about
packets that have been sent well before I polled the socket to see if
there's any pending data.
Stephan -

I think your problem is that you are using the
UdpClient "helper function", then drilling down to the low-
level socket and trying to perform functions there. Its
been my experience that's its best to perform all of your
operations at the same "level" - check for data at the
same level your are reading it from.

When you set the ReceiveBuffer size to 0, you are
disabling the socket level buffers. When data is received
by the socket, it must attempt to forward it to the next
level buffer. With a normal socket, that means to the next
Receive() method in your app. With the UdpClient object,
that must not be the case. Something must be buffering
data within the UdpClient object.

My suggestion would be to just use a plain-old Socket
object, and try this again. In my tests, I noticed that
the socket did hold 1 datagram in its buffer before
dropping subsequent packets (and the size of the datagram
didn't seem to matter). I don't know why this is the case -
I'll keep investigating (unless of course someone else on
this list knows why :). You may have to account for that
in your code. Hope this sheds some light on your problem.

Rich Blum - Author
"C# Network Programming" (Sybex)
http://www.sybex.com/sybexbooks.nsf/Booklist/4176
"Network Performance Open Source Toolkit" (Wiley)
http://www.wiley.com/WileyCDA/WileyTitle/productCd-
0471433012.html
 
S

Stephan Steiner

I've been doing some more testing and came across the socket.Available
parameter. Funny enough, before reactivating my receiver thread,
socket.Available returns zero, but when I do a UdpClient.Receive() prior to
re-enabling the receiver thread, I can read out datagrams that have been
sent during the inactive period.
Either this is another funny issue with the computer at work (I'll test at
home to make sure), or UdpClient has its own buffer and keeps on reading
datagrams from the socket until its own buffer is full so I'll try using
sockets directly as a last hope attempt.

If anyone has any ideas, I'd really appreciate them.. if I can't ensure that
I get no old data, I have to create a really nasty workaround based on my
packet sequence numbers, which will certainly only make things worse and
lead to unwanted results in the end.

Stephan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top