unconnected udp socket not receiving anything

S

Stephan Steiner

Hi

I have a small program listening to UDP broadcast datagrams that are
periodically sent out. It will stop listening for a certain period if either
a sufficient number of packets has been received (this is triggered from a
class not in the sample code), or if there has been no data on the net for a
certain period. During the time where I don't want any packets, I set my
socket receive buffer size to zero.

The problem is, when I used a UDPClient, I was always getting data that was
sent during the period where no listening took place (and changing the
buffer size didn't help), so I'm using sockets directly. However, I don't
receive a single packet now and I have no clue why. sock.Available is always
zero, even if I send a thousand UDP datagrams during the active period.
Here's my code:

public class Receiver
{
IPEndPoint remoteSender;
EndPoint tempRemoteEP;
byte[] packet;
public Thread thread;
bool listening;
Timer tim;
TimerState s;
public int nbPackets;
int seqNo;
Socket sock;
int nbBytesRx;

public Receiver()
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Broadcast, 1);
remoteSender = new IPEndPoint(IPAddress.Any,0);
tempRemoteEP = (EndPoint)remoteSender;
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 0);
listening = false;
nbPackets = 0;
packet = new byte[1024];
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();
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)
{
if (sock.Available > 0)
{
this.nbBytesRx = sock.ReceiveFrom(packet, ref tempRemoteEP);
nbPackets++;
seqNo = BitConverter.ToInt16(packet, 0);
Console.Write(nbPackets.ToString() + ":" + seqNo.ToString() + " / " );
}
}
}

/**
* resumes the thread
*/
public void activate()
{
if (thread.ThreadState == ThreadState.Suspended || thread.ThreadState ==
ThreadState.SuspendRequested)
{
Console.WriteLine("activated");
tim.Change(5000, 5000);
if (sock.Available > 0)
{
Console.Write("pending data");
}
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 8192);
thread.Resume();
}
else
{
Console.WriteLine("thread was already running");
}
this.listening = true;
}

/**
* suspends the thread
*/
public void deactivate()
{
if (thread.ThreadState == ThreadState.Running)
{
Console.WriteLine("\r\ndeactivated. " + this.nbPackets.ToString() + "
packets received");
tim.Change(Timeout.Infinite,Timeout.Infinite); // disable timer for the
time being
sock.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, 0);
thread.Suspend();
}
else
{
Console.WriteLine("thread was already inactive");
}
this.listening = false;
this.nbPackets = 0;
}

public void shutDown()
{
if (thread.ThreadState == ThreadState.Suspended)
thread.Resume();
thread.Abort();
}

/**
* Callback for the timer. Checks whether it's time to suspend the thread
because no new packets
* are coming in
*/
public void timeToSleep(Object state)
{
//TimerState stat = (TimerState)state;
if (this.nbPackets > s.counter) // new packets received in current period
{
s.counter = this.nbPackets;
}
else
{
if (this.listening)
{
this.deactivate();
s.counter = 0;
}
}
}
}

public struct TimerState
{
public int counter;
public Timer tim;
}

and to test I use this code which periodically activates and deactivates the
receiver.

static void Main(string[] args)
{
Receiver rec = new Receiver();
while (true)
{
rec.activate();
Thread.Sleep(10000);
rec.deactivate();
Thread.Sleep(10000);
}
}

Any help would be much appreciated.

Regards

Stephan Steiner
 
R

Rich Blum

Stephan Steiner said:
The problem is, when I used a UDPClient, I was always getting data that was
sent during the period where no listening took place (and changing the
buffer size didn't help), so I'm using sockets directly. However, I don't
receive a single packet now and I have no clue why. sock.Available is always
zero, even if I send a thousand UDP datagrams during the active period.
Stephan -

I did not see where you bound the socket to the UDP port that the
broadcast packets are using:

IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);
sock.Bind(iep);

This enables the ReceiveFrom() method to accept packets destined
for UDP port 9050. Hope this makes sense.

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
 
R

Rich Blum

Stephan Steiner said:
Not only makes it sense, now it works the way it should :) Thanks a bunch.
But while we're at the subject, the thing with the socket buffer is still
somewhat bothering me. As you can see from the source, I'm setting the
socket receive buffer size to zero before going to sleep. When I wake back
up, I reset the buffer to its standard size. The thing is, while the socket
does not accept any new packets when the buffer size is zero, one packet -
the first one being sent after the buffer size is set to zero - is somehow
kept in the system, and as soon as I reset the buffer size to its normal
value, that packet is added to the buffer. Where is that packet coming from
and why is it kept while the rest is dumped? I suppose it has something to
do with an underlying driver but I find it rather weird that one single
packet is kept.. no reasonable device driver buffer should be limited to one
750byte datagram, should it? After all, the Ethernet MTU is 1500bytes so if
it's the NIC driver buffer, it should at least hold two of my datagrams.

This is exactly the behavior that I pointed out in an earlier post
to your other thread. I do not have an explanation for this. My guess
is that there must be a buffer somewhere between the socket buffer and
the application that is allowing one packet (regardless of size) to be
accepted. Maybe someone else knows more about this.
And another thing I'm wondering about: why does a socket, or UDPClient for
the matter, require a certain setup time? I found that in all my tests,
during my first data burst, there would be a gap in the reception. The first
12 packets would be received, then a buffer wold overflow and packets be
dropped until the receiver can somehow catch up. From that point on,
everything works as it should. During my tests I also found that if at the
very beginning (before even starting my thread), I send one packet and
receive it immediately thereafter, the socket/UDPClient seems to be properly
initialized and no packets of my first databurst will be lost. Is this a
known problem?

I have not experienced this problem. Since you are using a
background thread to read packets there is some set-up time necessary
for the thread to be created and get started. This may be causing your
initial packet drops, which clean up once the thread is established
and running.

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
I have not experienced this problem. Since you are using a
background thread to read packets there is some set-up time necessary
for the thread to be created and get started. This may be causing your
initial packet drops, which clean up once the thread is established
and running.
No, this isn't it. The thread is initialized and running well before I start
receiving packets. The same is also true for my two previous sender and
receiver (I mailed those to you a while back)... it takes much longer for
the first send/receive than for subsequent ones. When stepping through any
of those programs (the old ones were single threaded, now the receiver is
threaded but the sender is still a singlethread app), I notice that the
first send/receive command blocks for a period of about a second, and any
subsequent operations are performed as quickly as any other line I step
through in the debugger.

If we take the following snippet as an example:

UdpClient updClient = new UdpClient(localPort);
Byte[] packet = new Byte[packetSize];
int nBytesSent = 0;
Byte[] seqNr = null;
for (short i = 0; i < nbPackets; i++ )
{
seqNr = BitConverter.GetBytes(i);
packet[0] = seqNr[0];
packet[1] = seqNr[1];
nBytesSent = updClient.Send(packet, packet.Length, address, remotePort);
Console.WriteLine("Packet # " + i + " byte3 " + packet[2] + " byte2 "
+ packet [1] + " byte1 " + packet[0]);
Thread.Sleep(10);
}
The first run of the for loop will take significantly longer than any
subsequent loop. When debugging, the first time updClient.Send(..) is
called, the commandline window (I'm using it in a cli project) quickly comes
on screen, then disappears again as the Console.WriteLine line is executed.
This only happens during the first run of the loop. This leads me to believe
that somehow, the UdpClient (and sockets as well because my socket based
code exhibits the same issue) is only properly set up, once a send or
receive operation is made. I've tried this out on two different computers
having two different operating systems (W2k, XP) and this issue was present
on both so I'm leaning towards a software issue here. As a workaround, I
perform a send/receive during the setup phase of any sender / receiver
class, and then when I actually want to send / receive I can do so without
any delays (and in the case of receiving: without loosing packets).

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