Decoding a string c# - c#

I created TCP server that is distributing client's messages and run on a problem. When I'm sending Cyrillic messages through stream they're not decoding properly. Anyone knows how can I repair that?
Here's the code for sending the message:
var message = Console.ReadLine().ToCharArray().Select(x => (byte)x).ToArray();
stream.Write(message);`
Here's the code for receiving:
var numberOfBytes = stream.Read(buffer,0,1024);
Console.WriteLine($"{numberOfBytes} bytes received");
var chars = buffer.Select(x=>(char)x).ToArray();
var message = new string(chars);

The problem is that a character in C# represents a 2-byte UTF-16 character. A cyrillic character is bigger than 255 in UTF-16, so you lose information when converting it to a byte.
To convert a string to a byte array, use the Encoding class:
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(Console.ReadLine());
To convert it back to a string on the receiver's end, write:
string message = System.Text.Encoding.UTF8.GetString(buffer);
Another problem is that Stream.Read does not guarantee to read all bytes of your message at once (Your stream does not know that you send packets with a certain size). So it could happen, for example, that the last byte of the received byte array is only the first byte of a 2-byte character, and you receive the other byte the next time you call Stream.Read.
There are several solutions to this issue:
Wrap the Stream in a StreamWriter at the sender's end and in a StreamReader at the receiver's end. This is probably the simplest method if you transmit only text.
Transmit the length of your message at the beginning of your message as an integer. This number tells the receiver how many bytes he has to read.

To convert a string to bytes, use System.Text.Encoding.GetBytes(string). I suggest you change the sending code to:
// using System.Text;
var messageAsBytes = Encoding.UTF8.GetBytes(Console.ReadLine());
To convert bytes to a string, use System.Text.Encoding.GetString(byte[]). If you receive UTF-8-encoded bytes:
// using System.Text;
var messageAsString = Encoding.UTF8.GetString(buffer);
Some suggested reading:
https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/
https://learn.microsoft.com/en-us/dotnet/api/system.text.encoding?view=netframework-4.7.2

Related

How to read binary data from TCP stream?

I have a device that sends data to another device via TCP. When I receive the data and try the Encoding.Unicode.GetString() method on the Byte array, it turns into unreadable text.
Only the first frame of the TCP packet (the preamble in the header) can be converted to text. (sender TCP docs, packet data).
This is my code so far. I have tried encoding as ASCII and there are no results either.
NetworkStream stream = tcpClient.GetStream();
int i;
Byte[] buffer = new Byte[1396];
while ((i = stream.Read(buffer, 0, buffer.Length)) != 0)
{
data = System.Text.Encoding.Unicode.GetString(buffer, 0, i);
data = data.ToUpper();
Console.WriteLine($"Data: {data}");
}
This just prints the same unreadable string seen in the "packet data" link above. Why is this happening? The official device doc says it is encoded in little endian. Am I missing something? I am new in handling TCP data transmission.
There is nothing in the linked documentation to indicate that there is any textual data at all, with exception for the "preamble", that is a fixed, four letter ascii-string, or an integer with the equivalent value, whatever you prefer.
It specifies a binary header with a bunch of mostly 32-bit integers, followed by a sequence of frames, where each frame has 3 32-bit numbers.
So I would suggest using wrapping your buffer in a memory stream and use BinaryReader to read values, according to the format specification.
Note that network communication typically uses big-endian encoding, but both windows and your device uses little-endian, so you should not have to bother with endianess.

Send UTF-8 string from Android to C#

I've been trying to accomplish a simple text transmission from my Android app to my C# server (asmx server), sending the simplest string - and for some reason it never works. My Android code is as following (assume that the variable 'message' holds the string as received from an EditText, which is UTF-16 as far as I'm concerned):
httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(POST_MESSAGE_ADDRESS);
byte[] messageBytes = message.getBytes("utf-8");
builder.addPart("message", new StringBody(messageBytes.toString()));
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
So I get something simple for my message, say a 10 bytes array. In my server, I have a function set to that specific address; its code is:
string message = HttpContext.Current.Request.Form["message"];
byte[] test = System.Text.Encoding.UTF8.GetBytes(message);
Now after that line the byte array ('test') has the exact same value as the result of the ToString() function I called in the app. Question is, how do I convert it to normal UTF-8 text to display?
Note: I have tried sending the string normally as a string content, but as far as I understood the default coding is ASCII so I got a lot of question marks.
Edit: Now I'm looking for some conversions solutions and trying them, but my question is also if there's a simpler way to do that (perhaps BinaryBody in the android, or different coding?)
Problem is in following lines:
byte[] messageBytes = message.getBytes("utf-8");
builder.addPart("message", new StringBody(messageBytes.toString()));
First you are transforming your UTF-16 string message into UTF-8 encoded messageBytes only to convert them back to UTF-16 string in next line. And there you are using StringBody constructor that will use ASCII encoding as default.
You should replace those lines with:
builder.addPart("message", new StringBody(message, Charset.forName("UTF-8")));

C# Sending Hex string to tcp socket

I'm trying to send a hex string to a tcp socket. I have some problems with the format or conversion of this string, cause I'm not very sure what the format its using.
I've written a WindowsPhone app which is working fine based on Socket Class.
This app emulates request, that are normaly send from a desktop program to a device which hosts a webservice.
Via wireshark, I found out, that the webservice will accept an input stream (think its in hex) and returns a 2nd. hex stream which contains the data I need.
So the desktop app is sending a stream
and Wireshark shows when :
Data (8 bytes)
Data: 62ff03fff00574600
Length: 8
Now I've tried a lot to reproduce this stream. I thougt, it used to be a UTF8 string and converted this stream to this format. But every time I send it, is see in Wireshark the following output: 62c3bf03c3bf00574600
As far as i've investigated 62 = b but ff send always c3bf.
Does somebody know how to send this stream in the right format?
Cheers,
Jo
The socket transport shouldn't care, the content of a TCP packet is binary representing "whatever".
From the code you pointed to in the comments:
byte[] payload = Encoding.UTF8.GetBytes(data);
socketEventArg.SetBuffer(payload, 0, payload.Length);
...
response = Encoding.UTF8.GetString(e.Buffer, e.Offset, e.BytesTransferred);
response = response.Trim('\0');
At the end of the socket send/receive (data == response). If that isn't occurring you need to figure how where the problem is. The first step is to write some very simple code like so:
string source = "your problem text string";
byte[] encode = Encoding.UTF8.GetBytes(source);
target = Encoding.UTF8.GetString(encode, 0, encode.Length);
Debug.Assert(source == target);
If that works, then output the 'encode' array can check to make sure that is contained in the packet data where it is being send, then verify that that is what is being received. If you are sending the right data but receiving it corrupted you have serious problems ... I doubt you find that but if so write a very simple test program that sends and receives on the same machine (localhost) to see if it is repeatable.
If I had to guess I would say that the characters being encoded are not Unicode or that Win phone doesn't properly support it (Proper unicode support).
As long as you don't know the protocol / the encoding the server expects you can only replay the known messages, like the bytes you provided in your question.
Therefore you just define directly the byte array like this:
byte[] payload = new byte[] {0x62, 0xff, 0x03, 0xff, 0xf0, 0x05, 0x74, 0x60};
and send it over the socket like you did with the encoded string before. The server should now accept the message like it was sent by the client you sniffed.

C# Network Stream still contains old data after read

New to TCP socket communications in C#, having a problem where I send some data across the network stream from my client app, then read it from my server app. Data comes through fine the first time, but the next time I try to send data, the old data is still in the network stream and just gets overridden up to whatever the length of the new data is. This is causing issues when trying to parse the data in the stream. I have tried adding a null termination but it doesn't seem to have any effect.
How can I empty the network stream before sending more data across?
We send a string such as this:
1|0|bob|cornell|9/14/2012 12:49:34 AM
Then another one like this:
1|0|jim|horne|9/14/2012 12:49:34 AM
But the second string goes through as :
1|0|jim|horne|9/14/2012 12:49:34 AMAM
...followed by a bunch of \0.
The last chunk is a DateTime, and it is failing to convert the string to a DateTime because of the extra AM. Even when appending \0 to the end of the string we are sending across the stream, it won't work. For example:
1|0|jim|horne|9/14/2012 12:49:34 AM\0M
It seems to treat the null termination as just another character, rather than a signal to stop reading the string.
It seems that "Flush" does nothing on NetworkStream types. Must be a dumb problem here, but any help is appreciated.
The client does this:
private static void writeToServer(MessagePacket message, NetworkStream clientStream)
{
clientStream.Write(message.ToBytes(), 0, message.ToBytes().Length);
}
The server does this:
byte[] rawMessage = new byte[4096];
while (true)
{
try
{
clientStream.Read(rawMessage, 0, 4096);
clientStream.Flush();
}
catch
{
break;
}
newPacket = new MessagePacket(rawMessage);
}
Stream.Read() returns the number of received bytes, the bytes after after that are undefined.
prefix your message with the number of bytes/chars to read ...
like: < integer>< delimeter char>< normal message>
on the receiver side, try finding the first match for the delimeter char ... parse the int in the part before that delimeter ... try reading the number of bytes/chars after the delimeter

What is the exact method to send an Image over network [An attempt using Sockets]

This is my Server side code:
public void ReceivingData(object sender, EventArgs e)
{
while (mysocket.Connected)
{
buffer = new byte[accepted.SendBufferSize];
int bytesRead = accepted.Receive(buffer);
MemoryStream Data = new MemoryStream(buffer);
if ( picbox.InvokeRequired)
{
picbox.Invoke(new MethodInvoker(delegate { picbox.Image = Image.FromStream(Data); }));
}
}
}
The connection gets established and the file is being received without any issue. However the image gets distorted on Transfer. I do not understand why this is happening. Here is the screenshot:
I remember i had to format the strings which i used to send over sockets using Encoding.ASCII.GetString(StringToFormat). What do i need to do in case of Images?
In your ReceivingData callback you may not receive all the data back in one pop. Some data can be partially received and the rest of it in a subsequent (or multiple) callbacks and it will be your task to re-assemble the original message.
You will need to define a protocol to ensure that you have read all necessary data.
You could for example use base64 to encode the image on the server and decode it on the client. You would need to know how many bytes you should anticipate. This can be done, either by prefixing your response with the total bytes that the client should anticipate or by having a special marker (such as byte value 0x00) to distinguish message boundaries.
Using Base64 will also have the effect of increasing file sizes by 33% since base64 basically encodes every 6bits of the incoming stream to an 8bit readable character. So for every 3 'real' bytes you would like to transfer you will need 4 encoded bytes.

Categories