Asynchronous socket, receive string messages - c#

Good evening, sorry in advance for writing so much but I don't know where the error is...
My client application is receiving from the server asynchronously. I want to transfer a bunch of stuff at once (the contents of an array, a couple of hundred bytes).
I want the server to be able to send "commands", and have a function on the client side act according to these commands, for example if the message from the server reads "print_hello", it should call a function that prints hello.
Now, it's my understanding that when receiving data asynchronously, I can't know how much of the data has been sent (or if more data than I expected has been sent), so I need to store all the data in a buffer, and when an "end of command" (for example, '!') sign has been received, it should know to call the function.
So far this makes sense to me, but I'm having trouble implementing it. In my DataReceived callback function, I have this code:
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
mainBuffer is declared as volatile static string mainBuffer = "";
The first line prints correctly, and goes through all of the data as expected. However, when I print out the mainBuffer, it only prints out the very first set of data I receieved, the rest does not get added to the buffer.
What could cause this? Thread safety issues? Am I not reading the latest value of mainBuffer? I can't use breakpoints to debug this.
Sample output:
Raw data: ABC
ABC
Raw data: DEF
ABC
RAW data: GHI
ABC
Small update, I tried using a volatile static int as well, and it increments and prints correctly after each DataReceived(). The string still does not get updated however.

Here is your problem "with the messing code lines!":
//of course the problem has noting to do with the string being volatile...
private volatile string mainBuffer = string.Empty;
byte[] buffer = new byte[1024];
while (networkStream.Read(buffer, 0, buffer.Length) > 0)
{
string data = System.Text.Encoding.UTF8.GetString(buffer);
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
}
Naturally the output of this code will be as you mentioned previously. Here is what is happening:
The string class in C# is an array of char start by pointer to the first char in the array and ends by the special "terminal" char \0.
When you create a byte array of n index, it will fill all indexes of the array with the default value of byte which is 0. but 0 is just equals the terminal char \0
byte b = (byte)`\0`;\\the value of b will be 0
So, When you call Read(buffer), the method will not trim the buffer to just fit the data read. so if the buffer size "here 1024" is larger than the data read, all the remaining bytes of the buffer will be equals to the terminal char '\0', So the array of chars of the generated string will be ABC\0\0\0\0... to the index 1024. When you add a string DEF to that it will add it at the last index of the char array "after last \0", the char array then will be ABC\0\0\0\0...DEF, but because of DEF is added after the terminal char(s) so the Console.Write will ignore all after the first \0!.
Also note while you debugging, if you point your mouse to the mainBuffer variable, you will see the actual data it contains maybe something like ABC\0\0\0\0..DEF\0\0\0\0..GHI
However to fix the problem and only generate a reliable string, Get the actual bytes read and generate the string only from it. So:
int dataRead = 0;
while ((dataRead = networkStream.Read(buffer, 0, buffer.Length)) > 0)
{
List<byte> actualBuffer = (new List<byte>(buffer)).GetRange(0, dataRead);
string data = System.Text.Encoding.UTF8.GetString(actualBuffer.ToArray());
Console.WriteLine("Raw data: {0}", data));
mainBuffer += data;
Console.WriteLine(mainBuffer);
}
It is wroth to mention here that you should consider using StringBuilder instead of string.

Related

How to check if my serial port is not receiving any more data in C#?

I am trying to determine whether I am receiving data or not, since every time I run my program I am expecting a different amount of data. Here is my code to illustrate:`
List<int> Receiverlist = new List<int>();
while (There is data from serialPort1 ) {
serialinput = serialPort1.ReadChar();
Receiverlist.Add(serialinput);
}`
Do I need to add \0 in the end of my list ?
You can use the BytesToRead property. It will show you whether data is in the received buffer. If so you can read it with one of the read methods.
In your code example you seem to read char by char
List<int> Receiverlist = new List<int>();
while (serialPort1.BytesToRead > 0)
{
string serialinput = serialPort1.ReadChar();
Receiverlist.Add(serialinput);
}
another possibility would be to read the entire buffer and parse the input afterwards:
if(serialPort1.BytesToRead > 0)
{
string serialinput = serialPort1.ReadExisting();
// parse the input according to your needs
}
Do I need to add \0 in the end of my list ?
It depends on what your purpose is with this char.
But to get the last element of a list you can just use:
int last = Receiverlist.Last();

C# How would set the output of this to a string?

So this is a section of code for my tcp client. This part is to convert the bytes recieved into characters. However, i would like to put some logic to it and to do that i need to set this output to a string. As it keeps printing out every character individually how would i do this? If you require anymore information feel free to ask.
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
Console.Write(Convert.ToChar(bb[i]));
Thanks in advace.
As per comments, if you want to decode a byte array in a particular encoding, just use Encoding.GetString. For example:
string text = Encoding.ASCII.GetString(bb, 0, k);
(Note that ASCII is rarely a good choice if the text is meant to be arbitrary human text. UTF-8 is usually a better option at that point, but then you need to bear in mind the possibility that a single character may be split across multiple bytes - and therefore multiple calls to Stream.Read.)
string str = "";
foreach (byte b in bb) str += Convert.ToChar(b);
Console.Write(str);

C# "Tag" 4-byte Hex Chunks for reconstruction to original string later

I am wrestling with a particular issue and like to ask for guidance on how I can achieve what I seek. Given the below function, a variable length string is used as input which produces a 4-byte Hex chunk equivalent. These 4-byte chunks are being written to an XML file for storage. And that XML file's schema cannot be altered. However, my issue is when the application which governs the XML file sorts the 4-byte chunks in the XML file. The result, is when I read that same XML file my string is destroyed. So, I'd like a way to "tag" each 4-byte chunk with some sort of identifier that I can in my decoder function inspite of the sorting that may have been done to it.
Encoding Function (Much of which was provided by (AntonĂ­n Lejsek)
private static string StringEncoder(string strInput)
{
try
{
// instantiate our StringBuilder object and set the capacity for our sb object to the length of our message.
StringBuilder sb = new StringBuilder(strInput.Length * 9 / 4 + 10);
int count = 0;
// iterate through each character in our message and format the sb object to follow Microsofts implementation of ECMA-376 for rsidR values of type ST_LongHexValue
foreach (char c in strInput)
{
// pad the first 4 byte chunk with 2 digit zeros.
if (count == 0)
{
sb.Append("00");
count = 0;
}
// every three bytes add a space and append 2 digit zeros.
if (count == 3)
{
sb.Append(" ");
sb.Append("00");
count = 0;
}
sb.Append(String.Format("{0:X2}", (int)c));
count++;
}
// handle encoded bytes which are greater than a 1 byte but smaller than 3 bytes so we know how many bytes to pad right with.
for (int i = 0; i < (3 - count) % 3; ++i)
{
sb.Append("00");
}
// DEBUG: echo results for testing.
//Console.WriteLine("");
//Console.WriteLine("String provided: {0}", strInput);
//Console.WriteLine("Hex in 8-digit chunks: {0}", sb.ToString());
//Console.WriteLine("======================================================");
return sb.ToString();
}
catch (NullReferenceException e)
{
Console.WriteLine("");
Console.WriteLine("ERROR : StringEncoder has received null input.");
Console.WriteLine("ERROR : Please ensure there is something to read in the output.txt file.");
Console.WriteLine("");
//Console.WriteLine(e.Message);
return null;
}
}
For Example : This function when provided with the following input "coolsss" would produce the following output : 0020636F 006F6C73 00737300
The above (3) 8 digit chunks would get written to the XML file starting with the first chunk and proceeding onto the last. Like so,
0020636F
006F6C73
00737300
Now, there are other 8-digit chunks in the XML file which were not created by the function above. This presents an issue as the Application can reorder these chunks among themselves and the others already present in the file like so,
00737300
00111111
006F6C73
00000000
0020636F
So, can you help me think of anyway to add a tag of some sort or use some C# Data Structure to be able to read each chunk and reconstruct my original string despite the the reordering?
I appreciate any guidance you can provide. Credit to AntonĂ­n Lejsek for his help with the function above.
Thank you,
Gabriel Alicea
Well, I am reluctant to suggest this as a proposed solution because it feels a bit too hackish for me.
Having said that; I suppose you could leverage the second byte as an ordinal so you can track the chunks and "re-assemble" the string later.
You could use the following scheme to track your chunks.
00XY0000
Where the second byte XY could be split up into two 4-bit parts representing an ordinal and a checksum.
X = Ordinal
Y = 16 % X
When reading the chunks you can split up the second byte into two words just like above and verify that the checksum aligns for the ordinal.
This solution does introduce a 16 character constraint on string length unless you eliminate the checksum and use the entire byte as an ordinal for which you can increase your string lengths to 256 characters.

Send a value by socket and read the value by reader.ReadInt32() changes value

I am trying to send a value by socket .So i have two parts in my project Client and server .
The client sends a value to server using this code :
System.IO.BinaryWriter binaryWriter =
new System.IO.BinaryWriter(networkStream);
binaryWriter.Write(1);
binaryWriter.Write(2);
binaryWriter.Flush();
So in other part i need to read the two values i mean 1 and 2;
So in server part i have this code :
static void Listeners()
{
Socket socketForClient = tcpListener.AcceptSocket();
if (socketForClient.Connected)
{
NetworkStream networkStream = new NetworkStream(socketForClient);
while (true)
{
List<int> variables = new List<int>();
using (var reader = new BinaryReader(networkStream))
{
for (int i = 0; i < 2; i++)
{
int t = reader.ReadInt32();
variables.Add(t);
}
}
}
}
}
As you can see i hold the values in variables list .but it doesn't work .i mean in server part i can't get the values 1 and 2 and my values is like this :841757955
best regards.
and my values is like this :841757955
Always worth sticking that number in the Windows calculator and convert that to hex. You get 0x322C3503.
Which looks a lot like ASCII, a string with 3 characters that encodes "5,2". In other words, your real code doesn't resemble your snippet at all, you don't actually use the BinaryWriter.Write(Int32) overload, you used BinaryWriter.Write(String).
Sure, that can't work, you can't write a string and expect it to be readable as raw integers. Fix your code.
As far as I can tell from your code, you are sending data as a string in binary format, this will yield bytes for the characters 1,2.
When you read the data back you try to get Int32 values.
There are two options here:
Read and write data as a string.
Client code:
binaryWriter.Write("1,2");
Server code:
string text = binaryReader.ReadString(); // "1,2"
OR Read and write data as integers.
Client code:
binaryWriter.Write(10);
binaryWriter.Write(20);
Server code:
int value1 = binaryReader.ReadInt32(); //10
int value2 = binaryReader.ReadInt32(); //20

receive bytes into an array from tcp client in c#

I want to receive bytes into an array from tcp client. I've an array of bytes dataToRecieve, in which I'm receiving those bytes.
But I've got some problems here, can anyone check my code:
while (true) {
try {
Socket handler = mainSocket.Accept();
byte[] dataToRecieve = new byte[handler.ReceiveBufferSize];
int[] dataArray = new int[1024];
handler.Receive(dataToRecieve);
//////SOME CODE
int i = handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch(Exception) {}
--------//////some code
Now I want to receive bytes into byte array & than convert it into the int array (however the data should be in an int array)........
Well, your code already has a problem here:
handler.Receive(dataToRecieve);
You're ignoring the value returned by Receive, to tell you how many bytes were actually read. That's almost always a bad idea. Likewise you're assuming you receive all the information you need in a single call. Usually you'd either have to loop until you'd read all the data - either by knowing that you expect a certain amount, or by reading until there is no more data.
Once you've got the data into a byte array, converting it into an integer array depends on the format in the byte array. You may be able to just use Buffer.BlockCopy, but that's only if the endianness in the byte array matches the endianness in memory. Alternatively, you can simply create an array of the right size, and write a loop:
int[] integers = new byte[size / 4];
for (int i = 0; i < integers.Length; i++)
{
integers[i] = BitConverter.ToInt32(bytes, i * 4);
}
However, again you need to consider the endianness. My MiscUtil library has an EndianBitConverter class which allows you to specify the endianness of your data.

Categories

Resources