TCP - duplex - mode analysis xml messages with and without endian

Markus Freitag 3,791 Reputation points
2021-06-02T17:14:55.747+00:00

Hello,

<users>
  <user age="42">John Doe</user>
  <user age="39">Jane Doe</user>
</users>

//or

<root>
  <user age="42">John Doe</user>
  <user age="39">Jane Doe</user>
</root>

I need to exchange an xml message via socket.
How can I make sure that the whole message was received? Is there a standard procedure?

private byte[] ReadBytes()
{
    try
    {
        NetworkStream stream = _client?.GetStream();

        byte[] bytes = new byte[count];
        int readCount = 0;

        while (readCount < count)
        {
            if (stream.DataAvailable)
            {
                int leftBytes = count - readCount;
                int readBytes = stream.Read(bytes, readCount, leftBytes);

// here is wrong not good, because is not sure I receieved the close element, the whole message
                byte[] bytesNew = new byte[readBytes];
                Array.Copy(bytes, bytesNew, readBytes);
                return bytesNew;
Developer technologies | C#
{count} votes

4 answers

Sort by: Most helpful
  1. Anonymous
    2021-06-02T20:54:01.59+00:00

    Hello,

    You can try using this code:

    private static byte[] ReadBytes()
        {
            System.Net.Sockets.TcpListener Listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 5000);
    
            Listener.Start();
    
            System.Net.Sockets.TcpClient TcpClient = Listener.AcceptTcpClient();
            System.Net.Sockets.NetworkStream NetworkStream = TcpClient.GetStream();
            Byte[] Bytes = { };
            int Index = 0;
    
            while(NetworkStream.DataAvailable == true)
            {
                Array.Resize(ref Bytes, Index + 1);
                Bytes[Index] = (byte)NetworkStream.ReadByte();
                Index += 1;
            }
            return Bytes;
        }
    

    This code assumes that the port you are listening on is 5000.

    1 person found this answer helpful.

  2. Timon Yang-MSFT 9,606 Reputation points
    2021-06-04T07:55:49.263+00:00

    Please try the following code, I use it to transfer xml between client and server without any problem, please check if it suits you.

           static void Main(string[] args)  
            {  
                string xml =File.ReadAllText(@"C:\Users\timony\Desktop\test.txt");  
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(xml);  
                Connect("127.0.0.1", data);  
            }  
            static void Connect(String server, Byte[] data)  
            {  
                try  
                {  
                    Int32 port = 13000;  
                    TcpClient client = new TcpClient(server, port);  
      
                    NetworkStream stream = client.GetStream();  
      
                    stream.Write(data, 0, data.Length);  
      
                    data = new Byte[256];  
      
                    String responseData = String.Empty;  
      
                    Int32 bytes = stream.Read(data, 0, data.Length);  
                    responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);  
                    Console.WriteLine("Received: {0}", responseData);  
      
                    stream.Close();  
                    client.Close();  
                }  
                catch (ArgumentNullException e)  
                {  
                    Console.WriteLine("ArgumentNullException: {0}", e);  
                }  
                catch (SocketException e)  
                {  
                    Console.WriteLine("SocketException: {0}", e);  
                }  
      
                Console.WriteLine("\n Press Enter to continue...");  
                Console.Read();  
            }  
    

    Server:

           public static void Main()  
            {  
                TcpListener server = null;  
                try  
                {  
                    // Set the TcpListener on port 13000.  
                    Int32 port = 13000;  
                    IPAddress localAddr = IPAddress.Parse("127.0.0.1");  
      
                    // TcpListener server = new TcpListener(port);  
                    server = new TcpListener(localAddr, port);  
      
                    // Start listening for client requests.  
                    server.Start();  
      
                    // Buffer for reading data  
                    Byte[] bytes = new Byte[256];  
                    String data = null;  
      
                    // Enter the listening loop.  
                    while (true)  
                    {  
                        Console.Write("Waiting for a connection... ");  
      
                        // Perform a blocking call to accept requests.  
                        // You could also use server.AcceptSocket() here.  
                        TcpClient client = server.AcceptTcpClient();  
                        Console.WriteLine("Connected!");  
      
                        data = null;  
      
                        // Get a stream object for reading and writing  
                        NetworkStream stream = client.GetStream();  
      
                        int i;  
      
                        // Loop to receive all the data sent by the client.  
                        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)  
                        {  
                            // Translate data bytes to a ASCII string.  
                            data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);  
                            Console.WriteLine("Received: {0}", data);  
      
                            // Process the data sent by the client.  
                            data = data.ToUpper();  
      
                            byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);  
      
                            // Send back a response.  
                            stream.Write(msg, 0, msg.Length);  
                            Console.WriteLine("Sent: {0}", data);  
                        }  
      
                        // Shutdown and end connection  
                        client.Close();  
                    }  
                }  
                catch (SocketException e)  
                {  
                    Console.WriteLine("SocketException: {0}", e);  
                }  
                finally  
                {  
                    // Stop listening for new clients.  
                    server.Stop();  
                }  
      
                Console.WriteLine("\nHit enter to continue...");  
                Console.Read();  
            }  
    

    102378-capture.png


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

  3. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2021-06-16T15:15:35.32+00:00

    there are couple things to understand about tcp/ip.

    first TCP/IP is a stream protocol, meaning the sender sends bytes and the receiver receives bytes. It is called reliable, because unlike UPD, packets are received in the same order they are sent. There is no definition of datagrams (logical data). That is up to your application to add a datagram protocol. typically the datagram has a total byte count (if known in advance) or termination indicator.

    the protocol is duplex, in that their are two streams. TCP/IP stream access mimics file access, though without the end of file indicator. Also TCP/IP is buffered, so a sender may need to flush to force the last bytes of a datagram to be sent.

    to send xml as datagrams is doable, but fragile. an invalid xml fragment, would break the next datagram.

    if you need to know if the datagram was received then the receiver needs to send a response.

    sender:

    while (connection.Open)
    {
    await sendMessage(...);
    var ok = await receiveResponse(...)
    }

    receiver:

    while (connection.Open)
    {
    var msg = await receiveMessage(...);
    await sendReceivedMessage(...);
    await processMessage(...)

    }


  4. Markus Freitag 3,791 Reputation points
    2021-06-06T06:32:36.543+00:00

    Hello,

          **I couldn't send a comment.** I go this way.  
    

    Thanks.

    Unfortunately it is not enough. The client is only unique. I need duplex mode.

    • When the server sends multiple XML messages.
    • When the server sends incomplete messages.
    • When the server sends fragmented messages in the time window.
    • How can I solve this with the timer?
         string data = @"<ROOT> <ALIVE_REQ item=""1""/> </ROOT>ppp<ROOT> <ALIVE_REQ item=""2""/>\r\n</ROOT>ppppppp<ROOT> <ALIVE_REQ item=""3""/>\r  </ROOT><ROOT> <ALIVE_REQ item=""4""/> </ROOT>";  
               serverSendTextbox1.Text = data;  
      
      
      
      
               string xmlelement = "ROOT";  
               int startIndex, endIndex;  
               string received;  
      
               startIndex = data.IndexOf($"<{xmlelement}>");  
               while (startIndex > -1)  
               {  
                   endIndex = data.IndexOf($"</{xmlelement}>") + $"</{xmlelement}>".ToString().Length;  
      
                   if (startIndex > -1 && endIndex > -1)  
                   {  
                       received = data.Substring(startIndex, endIndex - startIndex);  
                       data = data.Substring(endIndex, data.Length - endIndex);  
                       startIndex = data.IndexOf($"<{xmlelement}>");  
                   }  
               }  
      

    or

     if (stream.DataAvailable)  
                            {  
                                read = stream.Read(buffer, 0, buffer.Length);  
                                data += Encoding.UTF8.GetString(buffer, 0, read);  
      
                                startIndex = data.IndexOf($"<{xmlelement}>");  
                                while (startIndex > -1)  
                                {  
                                    endIndex = data.IndexOf($"</{xmlelement}>");  
                                    if (endIndex == -1)  
                                    {  
                                        TimeoutTimerReadMessage = new Timer((o) =>  
                                        {  
                                            data = "";  
                                        }, null, 3000, -1);  
      
                                        break;  
                                    }  
                                    else  
                                    {  
                                        TimeoutTimerReadMessage?.Dispose();  
                                        TimeoutTimerReadMessage = null;  
                                    }  
      
                                    endIndex  += $"</{xmlelement}>".ToString().Length;  
      
                                    if (startIndex > -1 && endIndex > -1)  
                                    {  
                                        received = data.Substring(startIndex, endIndex - startIndex);  
                                        _receivedDataQueue.Enqueue(received);  
                                        int count = _receivedDataQueue.Count;  
      
                                        data = data.Substring(endIndex, data.Length - endIndex);  
                                        startIndex = data.IndexOf($"<{xmlelement}>");  
                                    }  
                                }                              
                            }  
      
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.