Dumpen
Dumpen

Reputation: 1672

Ending a thread safely when using UDP Receive

I'm creating a thread that runs a UDP Client that receives a message, after it receives the message I want to close the UDP client and then end the thread, but I dont know how to end the thread since "Receive" always runs until it gets an answer.

This is my code so far:

private void RecieveChallenge()
{
    UdpClient client = new UdpClient(26000);
    IPEndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);

    Byte[] receivedBytes = client.Receive(ref remoteIp);
    string ipAddress = Encoding.ASCII.GetString(receivedBytes);
}

The important line is client.Receive(ref remoteIp);

Here is how I start my thread:

Thread recieveChallengeThread = new Thread(new ThreadStart(RecieveChallenge));
recieveDataThread.Start();

Upvotes: 8

Views: 15050

Answers (5)

Luc Pattyn
Luc Pattyn

Reputation: 1

An improvement on Jacek's above solution uses a second while loop; doing so a time-out does not throw away a possible datagram that was being received at the moment a time-out fires (the original code calls for another ReceiveAsync on every time-out ignoring any ongoing Receive):

while (_monitoringThreadIsRunning {        
    var receiveTask = _udpClient.ReceiveAsync();                
    while (_monitoringThreadIsRunning {        
        var timeoutTask = Task.Delay(ReceiveTimeout);
        if (timeoutTask == await Task.WhenAny(timeoutTask, receiveTask))
            continue;
        UdpReceiveResult udpReceiveResult = await receiveTask;
        // handle udpReceiveResult.Buffer
        break; // return to outer loop, launching another Receive
    }
}

PS: I would have put this in a comment, however as it is my first contribution here, I was lacking the necessary reputation points to do so.

Upvotes: 0

Jacek Plesnar
Jacek Plesnar

Reputation: 505

I was looking for good answer and thanks to colleague advice I made following solution (seems to work fine)

while (_monitoringThreadIsRunning)
{                        
   var timeoutTask = Task.Delay(ReceiveTimeout);
   var receiveTask = _udpClient.ReceiveAsync();

   if (timeoutTask == await Task.WhenAny(timeoutTask, receiveTask))
      continue;

   UdpReceiveResult udpReceiveResult = await receiveTask;
   // handle udpReceiveResult.Buffer
}

For stopping you need to set _monitoringThreadIsRunning to false. It works without any exceptions.

Upvotes: 1

M.Babcock
M.Babcock

Reputation: 18965

client.Receive will return an empty byte[] when the connection is closed. You should just have to close the connection and change the provided code to:

private void RecieveChallenge()
{
    UdpClient client = new UdpClient(26000);
    IPEndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);

    Byte[] receivedBytes = client.Receive(ref remoteIp);
    if (receivedBytes == null || receivedBytes.Length == 0)
        return;
    string ipAddress = Encoding.ASCII.GetString(receivedBytes);
}

Though you'll probably want RecieveChallenge to return a boolean indicating whether it is closed or not (of course ignoring the fact that your thread will only ever receive one message).

Upvotes: 8

jordanhill123
jordanhill123

Reputation: 4182

If you want to wait for it to end before continue on your current thread, you can use

recieveDataThread.Join();

Otherwise, thread closes as soon as the last line completes.

If you want to end it early, you can use

recieveDataThread.Abort(); 

from another thread.

Upvotes: 1

Al Kepp
Al Kepp

Reputation: 5980

Instead of Receive(), you can use BeginReceive()/EndReceive() - it is an asynchronous alternative.

See MSDN: http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx

These methods use a common APM (asynchronous programming model) of .NET.

Upvotes: 2

Related Questions