Complete program hang when trying to call ReadLine() - c#

Consider the following:
private void Read()
{
StreamReader r = new StreamReader(clientObject.GetStream());
string str = r.ReadLine();
if ((str == null) || (str == "")) { Disconnect(); }
Client_dataReceived(str);
Read();
}
When I connect this client to a server, it hangs. When I break it with Intellisense,
"string str = r.ReadLine();" is highlighted, I assume this is what the program was working on just before it started hanging. Why does it hang like this? I have created applications previously the exact same way, they don't hang.
Thanks in advance!
EDIT:
I just tried this:
private void Read()
{
StreamReader r = new StreamReader(clientObject.GetStream());
string str;
while ((str = r.ReadLine()) != null)
{
Client_dataReceived(str);
}
}
But I get the same effect...

private void Read()
{
StreamReader r = new StreamReader(clientObject.GetStream());
string str;
while (!(String.IsNullOrEmpty(str=r.ReadLine())))
{
Client_dataReceived(str);
}
}

Because it is a recursive call with no exit. You call Read inside of Read. It does not matter where it breaks.
private void Read()
{
StreamReader r = new StreamReader(clientObject.GetStream());
string str = r.ReadToEnd();
if ((str == null) || (str == "")) { Disconnect(); }
Client_dataReceived(str);
}

You have a recursive call. You will eventually get a StackOverflowException. (How coincidental. I just realized that!)
Try this:
private void Read()
{
using (var r = new StreamReader(clientObject.GetStream()))
{
string str;
while ((str = r.ReadLine()) != null)
{
Client_dataReceived(str);
}
Disconnect();
}
}
NOTE: I intentionally removed your str == "" test, as returning an empty string doesn't mean you've read to the end of the stream, while a null return does. If you have a special case where the empty line is important to be triggered on, be sure to restore that test.
Now if the clientObject is something that waits for input, like a TcpClient, then you need to evaluate it differently. It would help if we knew what clientObject was.

I can't comment because of low reputation so I'm writing it here...
Try adding a return(); statement after disconnect(); in your first code snippet.

Related

How to correctly parse received serial data into lines?

I'm creating a program which communicates with a serial device which is constantly sending data. I'm reading data from device every 100ms (using a timer). I use port.ReadExisting() to receive all currently available data from the device then I try split it into lines, because I need to check some of the received data and the best way is to check lines. The problem occurs when device sends data which doesn't end with "\r\n" or '\n'.
In a perfect situation port.ReadExisting() returns: "sampletext\r\nsomesampletext\nsampletext\r\n
But a problem occurs when there's no CR or LF character at the end:
First time port.ReadExisting() returns this: "text\nsamp"
Second time port.ReadExisting() returns this: letext\r\ntext\r\n"
End result should look like this:
text
sampletext
text
But what I get looks like this:
text
samp
letext
text
My code:
This is the timer which runs every 100ms:
private void CommandTimer_Tick(object sender, EventArgs e)
{
BackgroundWorker seriaDataWorker = new BackgroundWorker();
seriaDataWorker.DoWork += (obj, p) => PrintSerialData();
seriaDataWorker.RunWorkerAsync();
}
BackgroundWorker which gets called by the timer:
private void PrintSerialData()
{
try
{
if (RandomReboot)
{
RebootWatch.Start();
}
if (COMport.IsOpen)
{
if (COMport.BytesToRead != 0)
{
SerialPrint(COMport.ReadExisting());
}
}
}
catch (System.IO.IOException SerialException)
{
return;
}
}
Function which parses received data into lines:
private void SerialPrint(string data)
{
using (var buffer = new StringReader(data))
{
string line = "";
while((line = buffer.ReadLine()) != null)
{
if (CheckForAnsw)
{
ReceivedCommandData = line;
if (ReceivedCommandData.Contains(AnswExpected))
{
ReceivedAnsw = true;
ReceivedLine = ReceivedCommandData;
ReceivedCommandData = "";
}
}
this.Invoke(new MethodInvoker(delegate
{
AppendText(TextBox_System_Log, Color.Black, line + "\r\n");
}
));
}
}
}
I know that the problem is that buffer.ReadLine() treats remainder of the string which doesn't end with a CR or LF character as a seperate line but I don't know how to fix it.
I tried using port.ReadLine() in the past but it is way slower and causes problems for me when serial ports get disconnected etc.
I don't think there's an easy way to handle this with the StringReader. Instead, you can split the string yourself:
private static string _buffer = string.Empty;
private static void SerialPrint(string data)
{
// Append the new data to the leftover of the previous operation
data = _buffer + data;
int index = data.IndexOf('\n');
int start = 0;
while (index != -1)
{
var command = data.Substring(start, index - start);
ProcessCommand(command.TrimEnd('\r'));
start = index + 1;
index = data.IndexOf('\n', start);
}
// Store the leftover in the buffer
if (!data.EndsWith("\n"))
{
_buffer = data.Substring(start);
}
else
{
_buffer = string.Empty;
}
}
private static void ProcessCommand(string command)
{
Console.WriteLine(command);
}
You can use AnonymousPipes to transport and buffer the incoming data and read them as lines to output them to somewhere.
Here is a little example which creates a server and client pipe stream, then writes data to the server in one task (with some newline in the data) and reads the data in a different task per line and outputs them to the console.
public class Program
{
public static async Task Main()
{
(var writer, var reader) = CreatePipe();
using (writer)
using (reader)
{
var writerTask = Task.Run(async () =>
{
writer.AutoFlush = true;
writer.Write("?");
for (int i = 0; i < 100; i++)
{
if (i % 10 == 9)
{
await writer.WriteAsync("!");
await writer.WriteAsync(Environment.NewLine);
await writer.WriteAsync("?");
}
else
{
await writer.WriteAsync((i % 10).ToString());
}
await Task.Delay(100);
}
writer.Close();
});
var readerTask = Task.Run(async () =>
{
while (!reader.EndOfStream)
{
var line = await reader.ReadLineAsync();
Console.WriteLine(line);
}
});
await Task.WhenAll(writerTask, readerTask);
}
}
public static (StreamWriter, StreamReader) CreatePipe()
{
var server = new AnonymousPipeServerStream(PipeDirection.Out);
var client = new AnonymousPipeClientStream(server.GetClientHandleAsString());
return
(
new StreamWriter(server, Encoding.UTF8),
new StreamReader(client, Encoding.UTF8)
);
}
}
Try to adapt this code to your use case and comment if there are difficulies.
Your issue with \r\n and \n can be covered by using Environment.NewLine. I'm not sure what AppendText does, but if you're using it to store the values, then you're overdoing it. What you need is to store all data first in a StringBuilder then process them, OR process each data and store them in managed type such as Array, to define each line separately. Only use the string in the presentation layer (if you have some GUI that you want the user to see the results).
So, what I suggest is to store the lines in StringBuilder Something like this :
private readonly StringBuilder _strDataBuilder = new StringBuilder();
private void PrintSerialData()
{
try
{
if (RandomReboot)
{
RebootWatch.Start();
}
if(COMport.IsOpen && COMport.BytesToRead != 0)
{
var data = COMport.ReadExisting();
if(!string.IsNullOrEmpty(data)) {
_strDataBuilder.Append(data);
}
}
}
catch (System.IO.IOException SerialException)
{
return;
}
}
private void SerialPrint()
{
var data = _strDataBuilder.ToString();
if(string.IsNullOrEmpty(data)) { return; }
var lines = data.Split(Environment.NewLine);
if(lines.Length == 0) { return; }
for(int x = 0; x < lines.Length; x++)
{
var line = lines[x];
if (CheckForAnsw)
{
ReceivedCommandData = line;
if (ReceivedCommandData.Contains(AnswExpected))
{
ReceivedAnsw = true;
ReceivedLine = ReceivedCommandData;
ReceivedCommandData = "";
}
}
this.Invoke(new MethodInvoker(delegate
{
AppendText(TextBox_System_Log, Color.Black, line + Environment.NewLine);
}
));
}
}
Storing them first would make things more maintainability and fixability when you want to add more processing steps or reuse the results.
Although the SerialPrint() is unnessary if you just re-print the data in the GUI. As the data already separated in lines. So, if you do
TextBox_System_Log.Text = _strDataBuilder.ToString();
Directly, would list them in lines in the default color. However, if you intended to split them to process each line separately (to validate for instance), then it would be okay.
You can try like below code:
public void DataReceivedSerialPort(object sender, SerialDataReceivedEventArgs e)
{
readExistingData = "";
SerialPort sp = (SerialPort)sender;
sp.ReadTimeout = 100;
do
{
readExistingData = "";
try
{
readExistingData = sp.ReadLine();
if (readExistingData == "")
{
readExistingData = sp.ReadLine();
}
dataReadFromSerialPort += readExistingData;
}
catch
{
try
{
readExistingData = sp.ReadExisting();
dataReadFromSerialPort += readExistingData + "\r\n";
}
catch { }
}
UI.insert_new_items_into_textBoxUARTLog(readExistingData);
} while (readExistingData != "");
}

How to read and write to a text file with nothing in it

So im making a simple register and login in unity and ive came across a wall. My code works fine if it has any character or word in it but with it blank the loop doesnt work because it is a while line != null. I know that is the problem but i dont know any other loops to use in this scenario. Im using streamreader so i can constantly update the file as i can close it.
v
if (Input.GetKeyDown(KeyCode.Return))
{
StreamReader sr = new StreamReader("C:/Users/jorda/OneDrive/2D GAME REMAKE/Assets/login.txt",true);
line = sr.ReadLine();
while (line != null)
{
change =false;
if (line == Logdetails)
{
Debug.LogWarning("Account already exists");
username.GetComponent<InputField>().text = "";
password.GetComponent<InputField>().text = "";
break;
}
else if (Username == "" || Password == "")
{
Debug.LogWarning("There is an empty field");
break;
}
else
{
change = true;
}
line = sr.ReadLine();
}//while loop ends
sr.Close();
if (change == true)
{
Write();
}
}
public void Write()
{
StreamWriter sw = new StreamWriter("C:/Users/jorda/OneDrive/2D GAME REMAKE/Assets/login.txt", true);
{
sw.WriteLine(Logdetails);
username.GetComponent<InputField>().text = "";
password.GetComponent<InputField>().text = "";
sw.Close();
SceneManager.LoadScene(1);
}
}
Use a do while loop, which makes sure the code runs at least once, meaning for empty files one of your else branches is executed:
do
{
change =false;
if (line == Logdetails)
{
...
}
...
}
while(line != null)

Application freezes while using IO C#

I don't know what causes the issue, but whenever I try to read from a text file in this situation, the application freezes.
private void btnCount_Click(object sender, EventArgs e)
{
int totalVotes = 0;
int votesFirst = 0;
int votesSecond = 0;
string firstClub;
string secondClub;
FileStream fs = null;
StreamReader sr = null;
if (tb1.Text == "" || tb2.Text == "")
{
MessageBox.Show("Fill in the fields");
}
else
{
firstClub = tb1.Text;
secondClub = tb2.Text;
try
{
fs = new FileStream("C:\\Users\\dluuk\\source\\repos\\PopularFootballClubs\\Polls\\bin\\Debug\\FootballClubs.txt", FileMode.Open, FileAccess.Read);
sr = new StreamReader(fs);
string s = sr.ReadLine();
while (s != null)
{
if (s.Contains(firstClub))
{
votesFirst++;
totalVotes++;
}
else if (s.Contains(secondClub))
{
votesSecond++;
totalVotes++;
}
}
}
catch (IOException ex)
{
MessageBox.Show(ex.Message);
}
catch (Exception)
{
MessageBox.Show("something wrong happened");
}
finally
{
lblTotal.Text = totalVotes.ToString();
lbl1.Text = votesFirst.ToString();
lbl2.Text = votesSecond.ToString();
if (sr != null) { sr.Close(); }
if (fs != null) { fs.Close(); }
}
}
}
I'm closing connection and the path is correct, because I don't get any exceptions at this current state so I really can't see the problem. Maybe you can help?
You aren't updating s at all, so your loop is infinite. It's reading the first line, then looping over and over again, using the same line each time because ReadLine() is not called again in the scope of the loop (and thus you never reach the end of the file - or even line 2).
You could change to something like this:
string s;
while ((s = sr.ReadLine()) != null)
{
if (s.Contains(firstClub))
{
votesFirst++;
totalVotes++;
}
else if (s.Contains(secondClub))
{
votesSecond++;
totalVotes++;
}
}
As a side note, you should put using statements around your Streams. They are disposable and you won't need to handle it manually.
while (s != null)
You never change s in the loop, so it gets stuck in an infinite loop. Update s at the end of the loop:
while (s != null)
{
// do stuff
s = sr.ReadLine();
}

Console C# call nested function

Hey guys can you tell me how should can I call "print: if . It never goes inside print if . It loops out.
static void Main(string[] args)
{
if (commands == "Read" || commands == "read")
{
fileread obj = new fileread();
lcsString = obj.getlcs();
commands = Console.ReadLine(); // If command = print I want it go to print but it never goes . it loops out
}
else if (commands =="print")
{
}
}
You can use while, here you go..
while (!commands.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
if (commands.Equals("read", StringComparison.OrdinalIgnoreCase))
{
fileread obj = new fileread();
lcsString = obj.getlcs();
}
else if (commands == "print")
{
// print ...
}
commands = Console.ReadLine();
}
It is not clear what you asking but looks like there is an option;
Moving your commands = Console.ReadLine() outside in your if statement. Like;
commands = Console.ReadLine();
if (commands == "Read" || commands == "read")
{
fileread obj = new fileread();
lcsString = obj.getlcs();
}
else if (commands =="print")
{
}
Because if your first if statement works, that's mean your command is Read or read. After that, your program doesn't go your else if part. It goes outside of your if statement.

Writing and reading using socket

This is my code
using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;
public class s_TCP : MonoBehaviour {
internal Boolean socketReady = false;
TcpClient mySocket;
NetworkStream theStream;
StreamWriter theWriter;
StreamReader theReader;
String Host = "198.57.44.231";
Int32 Port = 1337;
string channel = "testingSona";
void Start () {
setupSocket();
//string msg = "__SUBSCRIBE__"+channel+"__ENDSUBSCRIBE__";
string msg = "Sending By Sona";
writeSocket(msg);
readSocket();
}
void Update () {
//readSocket();
}
public void setupSocket() {
try {
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e) {
Debug.Log("Socket error: " + e);
}
}
public void writeSocket(string theLine) {
if (!socketReady)
return;
String foo = theLine + "\r\n";
theWriter.Write(foo);
theWriter.Flush();
}
public String readSocket() {
if (!socketReady)
return "";
if (theStream.DataAvailable){
string message = theReader.ReadLine();
print(message);print(12345);
return theReader.ReadLine();
}
else{print("no value");
return "";
}
}
public void closeSocket() {
if (!socketReady)
return;
theWriter.Close();
theReader.Close();
mySocket.Close();
socketReady = false;
}
}
Connection created. But message not writing into server and reading
How can i do it
I think you have taken this code from http://answers.unity3d.com/questions/15422/unity-project-and-3rd-party-apps.html, but I think there is an error in this code. I'll repeat here what I posted there.
The following code does not work correctly:
public String readSocket() {
if (!socketReady)
return "";
if (theStream.DataAvailable)
return theReader.ReadLine();
return "";
}
This caused me a headache for quite few hours. I think that checking DataAvailable on the stream is not a reliable way to check if there is data to be read on the streamreader. So you do not want to check for DataAvailable. However, if you just remove that, then the code will block on ReadLine when there is no more to read. So instead, you need to set a timeout for reading from the stream, so that you won't wait longer than (say) a millisecond:
theStream.ReadTimeout = 1;
And then, you can use something like:
public String readSocket() {
if (!socketReady)
return "";
try {
return theReader.ReadLine();
} catch (Exception e) {
return "";
}
}
This code isn't perfect, I still need to improve it (e.g., check what kind of exception was raised, and deal with it appropriately). And maybe there's a better way overall to do this (I experimented with using Peek(), but the -1 it returns I suspect is for when the socket closes, and not just when there is no more data to read for now). However, this should solve problems with the posted code, like those I was having. If you're finding data is missing from the server, then it's probably sitting in your reader stream, and won't be read until new data is sent from the server and stored in the stream such that theStream.DataAvailable returns true.

Categories