How to do a string compare with the incoming message - c#

I know it sounds simple but I got some trouble with it. I am trying to make a system with a pic Microcontroller (MCU) and an xamarin android app. The sending part from app to the pic MCU is solved but when I want to send data from the MCU to the app it won't go as flaweless. I am using a HC-06 as a bluetooth device for receiving and sending messages.
The code for receiving from the MCU to the app is:
public void beginListenForData()
{
try
{
inStream = btSocket.InputStream;
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
Task.Factory.StartNew(() => {
byte[] buffer = new byte[1024];
int bytes;
while (true)
{
try
{
Array.Reverse(buffer, 0, buffer.Length);
bytes = inStream.Read(buffer, 0, buffer.Length);
if (bytes > 0)
{
string valor = Encoding.ASCII.GetString(buffer);
System.Diagnostics.Debug.WriteLine(buffer);
System.Diagnostics.Debug.WriteLine(bytes);
System.Diagnostics.Debug.WriteLine(valor);
if (valor == "D0O")
{
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
break;
}
//Result.Text = Result.Text + "\n" + valor;
}
}
catch (Java.IO.IOException)
{
//Result.Text = string.Empty;
break;
}
}
});
}
As you perhaps could geuss the message I try to sent from the MCU is D0O (valor) when the comparison worked with the incoming message I want to debug write that is was successful with:
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
The next part is for checking what for data is coming in:
System.Diagnostics.Debug.WriteLine(buffer);
System.Diagnostics.Debug.WriteLine(bytes);
System.Diagnostics.Debug.WriteLine(valor);
What I noticed is the strange output (see image):
As you can see the message is cut into 2 parts every time. Does anyone has any idea why and how to solve it?
I did change the array order with:
Array.Reverse(buffer, 0, buffer.Length);
Because I did notice it entered in the wrong order. This did work to put it in the right order.
Little update:
I changed some line of code and it works more "flaweless"
while ((count = inStream.Read(buffer, 0, buffer.Length)) > 0)
But what is strange that the first bit gets sepparated from the rest of the receiving string. I am not sure what causes this problem if anyone has a idea?
Thanks in advance.

I found a solution for the problem I was facing. So I will share my answer and thought process so perhaps other people can use the same.
So what I thought was there is a receiving buffer that saves the incoming char's. If the buffer is read with streamReader.Read it returns an integer of the readed char's. So I made second buffer of the datatype string[].
If the string[0] is empty I would place in my first Char that was read by the streamReader.Read. If the string[0] is NOT empty it means that the first char is already been read so I put the incoming char into string[1]. This means that the message that was split up is now into string[0] and string[1]. So what if I could combine it and save it into a string variable. This was done by: string eindtekst = string.Join("", buf); and this gives me the string in one piece so I can compare it. It is importent to clear the both array's as you're done with the comparing otherwise there would be new data added. And as you perhaps can tell string[0] == null would never be true. So only string[1] get's overridden al the time and that means you're losing out on data.
public void beginListenForData()
{
try
{
inStream = btSocket.InputStream;
streamReader = new StreamReader(inStream);
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
char[] buffer = new char[256];
string[] buf = new string[2];
int bytes;
while (1)
{
try
{
if ((bytes = streamReader.Read(buffer, 0, buffer.Length)) > 0)
{
string tekst = new string(buffer, 0, bytes);
if(buf[0] == null)
{
buf[0] = tekst;
}
else
{
buf[1] = tekst;
}
string eindtekst = string.Join("", buf);
if (eindtekst == "D0O")
{
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
System.Diagnostics.Debug.WriteLine(eindtekst);
Array.Clear(buffer, 0, buffer.Length);
Array.Clear(buf, 0, buf.Length);
writeData("D2O");
}
streamReader.DiscardBufferedData();
}
}
catch (Java.IO.IOException)
{
break;
}
}
}
Thanks for all the help

Related

C# tcpclient not writing to socket...or maybe I'm not reading all of the response?

I'm trying to write a C# console app to interface with a PC Miler telnet server. I managed to get this to work in powershell, but my C# code is not working.
static void Main(string[] args)
{
byte[] ReadBuffer = new byte[1024];
string[] stringSeparators = new string[]{"READY"};
try
{
TcpClient Socket = new TcpClient("myServer", 8320);
if (Socket.Connected) {
NetworkStream netStream = Socket.GetStream();
string PCMSResponse = "";
// Check for the READY prompt
if (netStream.CanRead) {
int byteRead = 0;
while (netStream.DataAvailable) {
byteRead = netStream.Read(ReadBuffer, 0, ReadBuffer.Length);
PCMSResponse += Encoding.ASCII.GetString(ReadBuffer, 0 , byteRead).Trim();
}
} else {
Console.WriteLine("Cannot read from myServer");
}
Thread.Sleep(1000);
// Get New Trip
if (netStream.CanWrite) {
Byte[] PCMSCommandBuffer = Encoding.ASCII.GetBytes("PCMSNewTrip");
netStream.Write(PCMSCommandBuffer, 0 , PCMSCommandBuffer.Length);
Thread.Sleep(1000);
} else {
Console.WriteLine("Cannot write to myServer.");
}
if (netStream.CanRead) {
int byteRead = 0;
while (netStream.DataAvailable) {
byteRead = netStream.Read(ReadBuffer, 0, ReadBuffer.Length);
PCMSResponse += Encoding.ASCII.GetString(ReadBuffer, 0, byteRead).Trim();
}
} else {
Console.WriteLine("Cannot read from myServer");
}
string[] ResponseArray = PCMSResponse.Split(stringSeparators, StringSplitOptions.None);
int c = ResponseArray.Length - 2;
string TripID = ResponseArray[c].Replace(System.Environment.NewLine, "").Replace("\0", "");
Console.WriteLine(PCMSResponse);
}
}
catch (SocketException)
{
Console.WriteLine("Unable to connect to server")
}
}
Expected output
ALK PCMILER SERVER READY
pcmsnewtrip
53
READY
Actual output
ALK PCMILER SERVER READY
It seems like I am not actually writing to the server because if I were to write an invalid command to the server I would see an error like this:
ALK PCMILER SERVER READY
pmctripnew
NO SUCH FUNCTION
READY
I know I can write to the socket because I'm not getting my error message Cannot write to myServer.
Not sure what I'm doing wrong. :(
Let me know if you'd also like to see the powershell code.
EDIT - If you're going to edit this post, at least keep the expected output AS EXPECTED! Changing the expected output changes the intent of the post. (EG, if I want apples but you edit my post to ask for oranges, I'm not going to get the correct answer.)
So the issue turns out to be that the NetworkStream.Write method does not end a string with a line terminator. As a result, when I wrote my PCMSCommandBuffer bytes to the stream, the command was never processed by the server (because its waiting for more of the command or the enter key to let it know you're done). My solution was to assign the stream to a StreamWriter. Then I can use the WriteLine method whichdoes send a line terminator.
streamWriter = new StreamWriter(netStream);
// Get New Trip
if (netStream.CanWrite) {
Byte[] PCMSCommandBuffer = Encoding.ASCII.GetBytes("PCMSNewTrip");
//netStream.Write(PCMSCommandBuffer, 0 , PCMSCommandBuffer.Length);
streamWriter.WriteLine("PCMSNewTrip");
//netStream.Flush();
streamWriter.Flush();
Console.WriteLine(PCMSCommandBuffer.Length + " PCMSNewTrip");
Thread.Sleep(1000);
} else {
Console.WriteLine("Cannot write to EW-APP1.");
}

C#/Unity - Convert StreamWriter.WriteLine to StreamWriter.Write and Message Bytes size as prefix

I've been researching and came to the conclusion that using StreamWriter.WriteLine is not the best idea. However, using StreamWriter.Write and prefixing the actual message bytes size and sending it from the client to the server so the server will know where to start reading and where to stop reading.
Here is working code I have so far:
public void Send(string header, Dictionary<string, string> data)
{
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
if (stream.CanRead)
{
socketReady = true;
}
if (!socketReady)
{
return;
}
JsonData SendData = new JsonData();
SendData.header = "1x" + header;
foreach (var item in data)
{
SendData.data.Add(item.Key.ToString(), item.Value.ToString());
}
SendData.connectionId = connectionId;
string json = JsonConvert.SerializeObject(SendData);
byte[] JsonToBytes = Encoding.ASCII.GetBytes(json);
byte[] lengthArray = BitConverter.ToInt32(JsonToBytes, 0);
stream.Write(lengthArray, 0, lengthArray.Length);
stream.Write(JsonToBytes, 0, JsonToBytes.Length);
stream.Flush();
Debug.Log("Client World:" + json);
}).Start();
}
This is how I send the data to the server. As you see I'm using writer.WriteLine(json); I know that I need to change that first to calculate the size of the message in bytes and send it as a prefix.
Here is how i read the data at the server:
//Console.WriteLine("Call");
if (!serverStarted)
{
return;
}
foreach (ServerClient c in clients.ToList())
{
// Is the client still connected?
if (!IsConnected(c.tcp))
{
c.tcp.Close();
disconnectList.Add(c);
Console.WriteLine(c.connectionId + " has disconnected.");
CharacterLogout(c.connectionId);
continue;
//Console.WriteLine("Check for connection?\n");
}
else
{
// Check for message from Client.
NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
string data = c.streamReader.ReadLine();
if (data != null)
{
OnIncomingData(c, data);
}
}
//continue;
}
}
for (int i = 0; i < disconnectList.Count - 1; i++)
{
clients.Remove(disconnectList[i]);
disconnectList.RemoveAt(i);
}
As you see I'm using c.streamReader.ReadLine(); which is reading the Line as a delimiter. I don't want that. I need to change it to check the message size in bytes, read it and then send it to OnIncomingData(c, data); as an actual message without the bytes prefix.
However, I don't know how to calculate the actual message size in the client, form it and send it. I'm also not aware how to proceed it in the reading in the server.
Can you please review my code and make edits to my code so it will work in this manner and I can understand how it works?

TcpListener truncating byte array randomly

I am writing what is essentially an image backup server to store images. It is a one way service that will not return anything beyond a basic success or failure message to the client.
The issue that I am experienceing is that when I send a byte array through the network stream, it is being cut-off before the end of the stream at random locations. I do not have this issue when I run the server on my development machine and connect locally, but rather it only occurs when the server is deployed on a remote server.
When I send very small arrays ( < 512 bytes) the server recieves the entire stream successfully, but on streams larger than 2000 bytes I experience issues. The code for the client is as follows:
try
{
TcpClient Voice = new System.Net.Sockets.TcpClient();
//Obviously I use the remote IP when it is deployed - but have altered it for privacy.
IPEndPoint BackupServer = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 57000);
Voice.Connect(BackupServer);
NetworkStream DataStream = Voice.GetStream();
byte[] buffer = new ASCIIEncoding().GetBytes(ImageData.GetXml());
DataStream.Write(buffer, 0, buffer.Length);
DataStream.Flush();
}
catch
{
}
try
{
buffer = new byte[4096];
int read = DataStream.Read(buffer, 0, buffer.Length);
MessageBox.Show(new ASCIIEncoding().GetString(buffer) + " : " + read.ToString());
}
catch
{
}
The client code executes without any errors or problems regardless of the size of data I send.
And the code for the server side is as follows:
private void BackMeUp(object voice)
{
TcpClient Voice = (TcpClient)voice;
Voice.ReceiveTimeout = 30000;
NetworkStream DataStream = Voice.GetStream();
try
{
bool ShouldLoop = true;
//int loops = 0;
int loops = -1;
byte[] input = new byte[2048];
byte[] buffer = new byte[0];
//while (ShouldLoop)
while(loops != 0)
{
loops = DataStream.Read(input, 0, 2048);
for (int x = 0; x < loops; x++)
{
Array.Resize(ref buffer, buffer.Length + 1);
buffer[buffer.Length - 1] = input[x];
}
//if (loops < 2048)
//{
//ShouldLoop = false;
//break;
//}
}
while (true)
{
StringReader Reader = new StringReader(new ASCIIEncoding().GetString(buffer, 0, buffer.Length));
DataSet DS = new DataSet();
DS.ReadXml(Reader);
if (DS.Tables.Count > 0)
{
if (DS.Tables["Images"].Rows.Count > 0)
{
foreach (DataRow row in DS.Tables["Images"].Rows)
{
//
}
}
}
string response = "Got it!";
DataStream.Write(new ASCIIEncoding().GetBytes(response), 0, response.Length);
DataStream.Flush();
Voice.Close();
break;
}
}
catch (Exception Ex)
{
File.WriteAllText("Elog.txt", Ex.Message + " " + (Ex.InnerException != null ? Ex.InnerException.ToString() : " no Inner"));
Voice.Close();
}
}
The server recieves the data fine, and closes the stream when it reaches the end, however the data is cut-off and I get an error when I try to rebuild the dataset.
I have the impression this has to do with the time it takes to send the stream, and I have played around with the Close and Flush commands but I feel like I'm just shooting in the dark. Any help would be appreciated.
Concise version of question: What factors are involved with a TcpListener that could cause a) the truncation of the stream. or b) premature closing of the stream prior to all bytes being read. When the listener in question is on a remote host rather than a local server.
The Read method doesn't have to return the number of bytes that you requested, or the entire stream at once. Especially if the stream is slow, it will be returned in small chunks.
Call the Read method repeatedly, and handle the data for each block that you get. The Read method returns zero when the stream is read to the end:
buffer = new byte[4096];
do {
int read = DataStream.Read(buffer, 0, buffer.Length);
if (read != 0) {
// handle the first "read" bytes of the buffer (index 0 to read-1)
}
} while (read != 0);
If you know that your buffer is enough for any stream, you can fill up the buffer and handle it afterwards:
buffer = new byte[4096];
int offset = 0;
do {
int read = DataStream.Read(buffer, offset, buffer.Length - offset);
offset += read;
} while (read != 0);
// handle the first "offset" bytes of the buffer (index 0 to offset-1)

C# Async Sockets Server Receive Problems

I have implemented my Server application regarding this post here: http://www.codeguru.com/csharp/csharp/cs_network/sockets/article.php/c8781#Client1
Sum up: I am using async Sockets ala BeginAccept(..), BeginReceive(..).
My Server is capable of handling mutliple clients and everything works fine until a client performas two or more synchronous send operation without waiting some time. The client does not get any error and so is not notified, that the server does not get the second message! If the client waits approx. 100ms after the first send operation, everything works fine.
I thought that when i use TCP i can ensure that the server receives the message. (Except there is an exception thrown)!
Could you provide me a solution to fix this.
Here are the WaitForData(..) & OnDataReceive(..) Methods that i implemented in the server
public void WaitForData(MyClient client)
{
try
{
if (pfnCallBack == null)
{
pfnCallBack = new AsyncCallback(OnDataReceived);
}
iarResult = client.Socket.BeginReceive(client.DataBuffer,
0, client.DataBuffer.Length,
SocketFlags.None,
pfnCallBack,
client);
}
catch (SocketException se)
{
MessageBox.Show("SocketException#WaitForData" + se.Message);
}
}
public void OnDataReceived(IAsyncResult asyn)
{
try
{
MyClient user= (MyClient)asyn.AsyncState;
int iRx = user.Socket.EndReceive(asyn);
byte[] receivedData = user.DataBuffer;
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(receivedData, 0, receivedData.Length);
memStream.Seek(0, SeekOrigin.Begin);
MyMessage msg = (MyMessage)binForm.Deserialize(memStream);
switch (msg.Command)
{
case (MyMessage.MyCommand.ConnId):
this.connId = (int) msg.MyObject;
tsslConnStatus.Text += " | ID: " + connId.ToString();
break;
case (MyMessage.MyCommand.Text):
MessageBox.Show(msg.MyObject.ToString());
break;
}
WaitForData(server);
}
catch (ObjectDisposedException ode)
{
MessageBox.Show("ObjectDisposedException#OnReceiveData" + ode.Message);
}
catch (SocketException se)
{
MessageBox.Show("SocketException#OnReceiveData" + se.Message);
}
}
The CLIENT calls a synchronous SEND METHOD TWICE or MORE! server INSTANCEOF MyClient
if (server.Socket.Connected)
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, message);
MyMessage = new MyMessage(something);
server.Socket.Send(ms.ToArray());
}
so, i think this code snippets must be enough for you to get the idea i was trying to use!
If you need further details or code snippets, just tell me i will post it!
Thanx!
TCP is stream based and not message based. One Read can contain any of the following alternatives:
A teeny weeny part of message
A half message
Excactly one message
One and a half message
Two messages
Thus you need to use some kind of method to see if a complete message have arrived. The most common methods are:
Add a footer (for instance an empty line) which indicates end of message
Add a fixed length header containing the length of the message
Update
Simple example having just length as header.
Server side:
var buffer = binaryFormmater.Serialize(myobj);
var length = buffer.Length;
networkStream.Send(length);
networkStream.Send(buffer, 0, buffer.Length);
Client side:
var header = new buffer[4];
// TODO: You need to make sure that 4 bytes have been read.
networkStream.Read(header, 0, 4);
var length = BitConverter.ToInt32(buffer);
var readbuffer= new byte[65535];
var bytesLeft = length;
var messageStream = new MemoryStream();
while (bytesLeft > 0)
{
var read = networkStream.Read(readbuffer, 0, bytesLeft);
messageStream.Write(readbuffer, 0, read);
bytesLeft -= read,
}
messageStream.Seek(0, SeekOrigin.Begin);
MyMessage msg = (MyMessage)binForm.Deserialize(messageStream);

SharpZipLib - ZipException "System.ArgumentOutOfRangeException" - Why am I getting this exception?

I'm using SharpZipLib to unzip files. My code has been working nicely for all zipfiles except the zip file what i am extracting now...
Got this exception:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: length
The exception is being thrown at size = s.Read(data, 0, data.Length);
Hereb is my code...
public static void UnzipFile(string sourcePath, string targetDirectory)
{
try
{
using (ZipInputStream s = new ZipInputStream(File.OpenRead(sourcePath)))
{
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
//string directoryName = Path.GetDirectoryName(theEntry.Name);
string fileName = Path.GetFileName(theEntry.Name);
if (targetDirectory.Length > 0)
{
Directory.CreateDirectory(targetDirectory);
}
if (fileName != String.Empty)
{
using (FileStream streamWriter = File.Create(targetDirectory + fileName))
{
int size = 2048;
byte[] data = new byte[2048];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Error unzipping file \"" + sourcePath + "\"", ex);
}
}
Looks like a bug to me. Fortunately, you have access to the code, so you should be able to see exactly where it's going wrong. I suggest you build a debug version of SharpZipLib, break on the line which is throwing the exception, and have a look at what it's actually testing.
It should be fine to read into a 2K buffer even if there's not 2K of data left.
(I wouldn't actually write the code quite how you have, but that's a different matter. I'd also move it into its own utility method - the act of copying all the data from one stream to another is pretty common. There's no need to tie it to zip.)
Looking at the code, you are reading the same set of bytes again (and advancing the position).
size = s.Read(data, 0, data.Length);
An example from here shows that the 2nd argument should be a moving position & not a fixed number.
Change your code int size = 2048; to int size = data.Length;. You won't take OutOfRange exception.
using (FileStream streamWriter = File.Create(targetDirectory + fileName))
{
int size = data.Length;
byte[] data = new byte[size];
while (true)
{
size = s.Read(data, 0, data.Length);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
}

Categories