Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot Append to Received String in UDP Listener C#

I have a Form that create a UDP object, in the UDP class a UDPClient is created and the received data is done in the BeginReceive Method using EndReceive.

When I print the string of the reveived data, after converting the byte[], to the console from within the beginreceive method, with text appended, only the received data prints not the appended text.

So it looks like the received data is incomplete.

When the string prints, the NewLine and appended "done" is not shown.

Any help would be great!!

Thanks

class Udp
{
    public EventHandler _dataReceived;

    public Udp()
    {

        int receiverPort = 1248;
        UdpClient receiver = new UdpClient(receiverPort);

        string discovery = "<?xml version=\"1.0\"?><ServiceQuery></ServiceQuery>";

        receiver.BeginReceive(new AsyncCallback( DataReceived), receiver);

        IPEndPoint end = new IPEndPoint(IPAddress.Broadcast, 1248);
        receiver.Send(Encoding.ASCII.GetBytes(discovery + "\0"), discovery.Length + 1, end);
}

private void DataReceived(IAsyncResult ar)
{
    UdpClient c = (UdpClient)ar.AsyncState;
    IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 1248);

    Byte[] receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);

    string receivedText = ASCIIEncoding.ASCII.GetString(receivedBytes);

    Console.WriteLine("\n");

    if(_dataReceived != null)
    {
        Console.Write(receivedIpEndPoint + ": " + receivedText + Environment.NewLine + "done");
       _dataReceived(receivedText, new EventArgs());
    }

    c.BeginReceive(new AsyncCallback(DataReceived), c);
}

    }    
like image 612
Robert de Klerk Avatar asked Jul 30 '15 11:07

Robert de Klerk


1 Answers

The simplest repro I can think of for this problem is this code:

    private void button1_Click(object sender, EventArgs e) {
        Byte[] receivedBytes = new byte[] { 0x48, 0x65, 0x6c, 0x00, 0x6c, 0x6f };
        string receivedText = Encoding.ASCII.GetString(receivedBytes);
        Console.Write(receivedText + ", you won't see this");
    }

Output after clicking the button several times:

   HelHelHelHel

Surely you now recognize the poison-pill in the receivedBytes array, it is the presence of the 0x00 byte that causes the output string to get cut short. Nothing beyond that byte makes it into the Visual Studio Output window.

Explaining this behavior requires a pretty deep dive in how Console.Write() in a Winforms app works and how it is capable of generating output, even though your program has no console. It is a long-winded story that isn't that likely to entertain anybody so I'll punt for the short version. With the Visual Studio Hosting Process debugger option enabled, Console.Write() is equivalent to Debug.Write(). Debug output is intercepted by the DefaultTraceListener class, it pinvokes OutputDebugString() to get the text to appear in the debugger trace window. These winapi functions takes C strings, a C string is zero-terminated to indicate the end of the string.

There are several ways to fix this, the programmer's way is to convert the byte[] array content to hex:

    Byte[] receivedBytes = new byte[] { 0x48, 0x65, 0x6c, 0x00, 0x6c, 0x6f };
    string receivedText = BitConverter.ToString(receivedBytes);
    Console.WriteLine(receivedText + ", you see this");

Output:

    48-65-6C-00-6C-6F, you see this
    48-65-6C-00-6C-6F, you see this
    48-65-6C-00-6C-6F, you see this

Or you might want to take a better look at the data you transmit, ensuring it is actually printable text that can be properly converted with Encoding.ASCII

like image 133
Hans Passant Avatar answered Oct 13 '22 18:10

Hans Passant