Taoh
Taoh

Reputation: 331

C# TCP Trying to send values as chars

I have some int values that all is within the 0-65535 range (16 bit). I need to transfer these across TCP connection, so I thought that converting these values to chars, and sending the chars, then decode the chars on the other end would fit the requirement.

First I create a string (the message) then I convert the numbers to chars and add them at the end of the message

        String unencodedMessage = "";

        for (int i = 0; i < 513; i++)
        {
            unencodedMessage += (char)i;
        }

I then story this message along with a TcpClient to use (GetMessage() and GetClient(). Converts the text as required (copy paste from: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx) verify that the TcpClient still appear to be valid (but as this is not guarantied I use the try).

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(internalMessages[i].GetMessage());
                TcpClient tmpClient = internalMessages[i].GetClient();
                if (tmpClient.Connected)
                {
                    try
                    {
                        NetworkStream stream = internalMessages[i].GetClient().GetStream();
                        stream.Write(data, 0, data.Length);
                    }
                    catch
                    {
                    }
                }

On the other end I receive the message and revert it back to a string like this.

            while (stream.DataAvailable)
            {
                int numberOfBytesRead = 0;

                numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);
                internalMessage += Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead);
            }

Once converted back I loop through the values and print them to verify everything is ok (note the String that is decoded is in index 1, of the list of strings), the 2nd. index should get me the chars back, and by converting those to ints I should get the 0-65535, I story these as text in a new string separated by : and write them in 1 go.

        public void UnencodeData(List<String> command)
        {
            String msg = "";
            for(int i = 0; i < command[1].Count();i++)
            {
                msg += ((int)command[1][i]) + ":";
            }
            Console.WriteLine(msg);
        }

I would expect a countup from 1:2:3: ... 512:513:, instead I get

Blockquote 0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:49:50:51:52:53:54:55:56:57:58:59:60:61:62:63:64:65:66:67:68:69:70:71:72:73:74:75:76:77:78:79:80:81:82:83:84:85:86:87:88:89:90:91:92:93:94:95:96:97:98:99:100:101:102:103:104:105:106:107:108:109:110:111:112:113:114:115:116:117:118:119:120:121:122:123:124:125:126:127:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:63:

Which is not quite what I expected, seems everything was going well until I got past the 7th bit of value.


What did I do wrong? what would have been a smarter approach to try to ship the values (expected range 0-10000). I could send the value as plain text, I just feel it is a waste.

As pointed out by several of the answers. The issue is the two lines I use here, with the Encoding.ASCII that cause the issue, and a more appropriate way instead of going over the Chars would be to convert the numbers directly to the Byte[] but I have chosen to not do so, as the write/read I use in my tool currently uses Strings as input. But that is beside the issue at hand, namely why the data did not match on the other end, so core issue Encoding.ASCII from official documentation gave the issue.

Byte[] data = System.Text.Encoding.ASCII.GetBytes(internalMessages[i].GetMessage());

internalMessage += Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead);

Working lines.

    Byte[] data = System.Text.Encoding.Unicode.GetBytes(internalMessages[i].GetMessage());

internalMessage += Encoding.Unicode.GetString(myReadBuffer, 0, numberOfBytesRead);

Upvotes: 0

Views: 756

Answers (2)

BartoszKP
BartoszKP

Reputation: 35891

This is because you are using the ASCII encoding, in which:

ASCII characters are limited to the lowest 128 Unicode characters, from U+0000 to U+007F.

In fact, probably none of other encodings will suit your needs (probably, as it's hard to guess what are your needs) - all of the use some kind of fall-back characters if they encounter a byte they can't encode, and you seem to just put some random bytes into a string.

The simplest solution seems to use a BitConverter. You may also consider Base64 encoding if you really want strings.

So, if you want to send text you have in strings just use: data = Encoding.UnicodeEncoding.GetBytes(unencodedMessage); (or UTF16 as you noted yourself). Otherwise, if you want to send some arbitrary values:

data = unencodedMessage.SelectMany(c => BitConverter.GetBytes(c)).ToArray();

Upvotes: 2

PaulK
PaulK

Reputation: 653

Why do you not just convert your short values to byte arrays using something like BitConverter?

byte[] bytes = BitConverter.GetBytes(...)

And then on the receiving end

ushort value = BitConverter.ToUInt16(...)

Or am I missing something?

Upvotes: 1

Related Questions