Pidi
Pidi

Reputation: 65

UDP Client - how to close after BeginReceive

I need to receive small UDP packets from within my ERP system (Dynamics Nav). I created a class with some code from the internet (first time I use code for UDP), added a COM interface and use the resulting DLL within Nav. It worked right away, but I realized that the udp.Close() function did not really close the thing, and I couldn´t instantiate the class a second time.

After looking at many topics about udp.BeginReceive() at stackoverflow and on other sites, I understand the reason for that. There needs to be a final udp.EndReceive call before closing the upd object.

Since the class is running in the background its using a callback function defined by udp.BeginReceive. The callback function then gets the data by calling udp.EndReceive and finally stores it to a string. Nav can retrieve that string whenever it wants that data trough a simple property.

    public string GetMessage { get { return(message); } }

    public void Start()
    {
        udp = new UdpClient(PORT_NUMBER);
        StartListening();
    }
    public void Stop()
    {
        udp.Close();
    }
    private void StartListening()
    {
        ar_ = udp.BeginReceive(Receive, new object());
    }
    private void Receive(IAsyncResult ar)
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT_NUMBER);
        byte[] bytes = udp.EndReceive(ar, ref ip);
        message = Encoding.ASCII.GetString(bytes);

        StartListening();
    }

Everthing is fine, except ...

Nav calls Start() which issues StartListening(), which defines the callback function. After receiving the data through udp.EndReceive it calls StartListening() again - this part is working fine.

As soon, as Nav calls the Stop() function however, the trouble starts, and I understand that this is, bacause there is no final call to EndReceive and thus an open session.

One may say, why don´t do an EndReceive() within the Stop() function before udp.Close()? Well, because I couldn´t find the correct parameters for that call.

Actually I do have a working class. I don´t try to close the session within the Stop() function but instead set a bool variable. The next time the callback function is issued, depending on that bool it doesn´t do a StartListening() but a upd.CLose() instead. And finally, to make sure there will be data to issue the callback function, I call my Send() function sending some single character.

While the following code is working perfectly, I know it´s kind of crazy:

    public string GetMessage { get { return(message); } }

    public void Start()
    {
        active = true;

        udp = new UdpClient(PORT_NUMBER);
        StartListening();
    }
    public void Stop()
    {
            active = false;  // force callback function to close session
            Send("x");       // issue callback function ... crazy
            //udp.Close();
    }
    private void StartListening()
    {
        ar_ = udp.BeginReceive(Receive, new object());
    }
    private void Receive(IAsyncResult ar)
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT_NUMBER);
        byte[] bytes = udp.EndReceive(ar, ref ip);
        message = Encoding.ASCII.GetString(bytes);

        if (active) StartListening(); else udp.Close();
    }

Does anyone have a hint how to issue EndReceive() within my Stop() function before calling udp.Close()?

Thanks in advance

Michael

Upvotes: 2

Views: 1539

Answers (1)

Pidi
Pidi

Reputation: 65

I recently found a solution just by using a Thread() instead of the async receive - works perfectly so far:

public class Bos_UDP
{
    private UdpClient udp;
    const int PORT_NUMBER = 15000;
    private String message = "";
    public Thread receiveThread;

    public string GetMessage { get { return(message); } }

    public void Start()
    {
        udp = new UdpClient(PORT_NUMBER);

        receiveThread = new Thread(ThreadReceive);
        receiveThread.Start();
    }
    public void Stop()
    {
            receiveThread.Abort(new object());
            udp.Close();
    }
    public void ThreadReceive()
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT_NUMBER);
        while (true)
        {
            var data = udp.Receive(ref ip);
            message = Encoding.Default.GetString(data);
        }
    }
    public void Send(string message)
    {
        UdpClient client = new UdpClient();
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse("255.255.255.255"), PORT_NUMBER);
        byte[] bytes = Encoding.ASCII.GetBytes(message);
        client.Send(bytes, bytes.Length, ip);
        client.Close();
    }
}

Upvotes: 2

Related Questions