Why do Pipes Hang When I try to Read Them? - c#

I am making a program that starts a child process and communicates via anonymous pipes. When I read from a pipe, the program hangs at the first ReadLine() call as seen in the following code method:
// Reads messages sent from module's process via anonymous pipe
internal string[] ReadPipe() {
try {
Log.Verbose("Checking read pipe");
// Check for sync message and return null if there is no message to receive
string pipeMessage = _pipeInReader.ReadLine(); // HANGS ON THIS LINE
if(pipeMessage == null || !pipeMessage.StartsWith("SYNC")) {
Log.Verbose("No message found in pipe");
return null;
}
// Return array of message lines
Log.Verbose("Received message from module {ModuleName}", _fileInfo.Name);
List<string> pipeMessageLines = new();
do {
pipeMessage = _pipeInReader.ReadLine();
pipeMessageLines.Add(pipeMessage);
Log.Debug(pipeMessage);
} while(pipeMessage != null && !pipeMessage.StartsWith("END"));
return pipeMessageLines.ToArray();
} catch(Exception e) {
Log.Error(e.ToString());
return null;
}
}
The code I am using to write to the pipe is the following:
// Sends a message to module's process via anonymous pipe
public static void WritePipe(string message) {
try {
Log.Verbose("Sending \"{Message}\" to kit pipe", message);
// Send sync message and wait for module process to receive it
Log.Verbose("Waiting for pipe drain");
_pipeOutWriter.Write("SYNC");
_pipeOut.WaitForPipeDrain();
// Send the specified message
Log.Verbose("Pipe drained. Sending message");
_pipeOutWriter.Write(message);
_pipeOutWriter.Write("END");
} catch(Exception e) {
Log.Error(e.ToString());
}
}
Why does it hang at that ReadLine() line?
Thanks in advance!

Without a proper minimal, reproducible example, it's impossible to say for sure. However, one glaring problem with your code is that when you write to the _pipeOutWriter object, you don't call Flush(). Assuming that's a TextWriter, by default it's going to buffer the data until the internal buffer is full, and not send anything to the underlying Stream until then.
By calling Flush(), you force it to flush its internal buffer and send the data right away.
If that does not address your question, please edit the question to improve it, making sure to provide a minimal, reproducible example, and any additional details about what you've tried so far to fix the problem and what specifically you need help with.

Related

Picking up changes from CouchDB in C#

I would like to pick up a specific document from _changes in couchDB.
Here is my query line, where FEED should be "continuous" and HEARTBEAT = "5000"
"?filter=_doc_ids&feed="+FEED+ "&include_docs=true&heartbeat="+HEARTBEAT;
I dont want to request the DB all the time to get the document, but for the DB to push the changes using the above parameters.
This means my c# code needs to keep a connection open for CouchDB to push the changes. This is being executed in its own thread.
I can get data using feed=longpoll, but the c# code just hangs when using continuous.
I'm thinking it has something to do with that im looking at it as an async to produce a .Result, but it should be a stream, so ive tried to do it using streams, but that just turned into a clusterf***. I spent too much time, and could not get it to work. It just stopped executing but not breaking with an exception, so i could not bughunt it.
Therefor i returned to this method, hoping it is possible with a little help :) It works for longpoll, but not for continuous.
internal void Listen (ref JobList jobList)
{
HttpResponseMessage result = null;
try
{
while (true)
{
result = _httpClient.SendAsync(_requestMessage).Result;
var stringResult = result.Content.ReadAsStringAsync();
var resultObject = JsonConvert.DeserializeObject<ImportJobsResponse>(stringResult.Result);
// Transfer the read objects to the jobList
if (null != resultObject)
{
foreach (ImportJob job in resultObject.results[0].doc.ImportJobs)
{
jobList.addJob(job);
}
}
}
} catch (JsonSerializationException jex)
{
// handle error, and write to log.
} catch (Exception ex) // Needs to find out what errors can come here when using httpclient
{
// handle error, and write log.
}
}
Can anybody help :) ty in advance.

Reading data from a serialport from different threads

Using this example I created two classes used to read a device on a serial port. The device is a laser which I can control (turn system/lasers on/off, read stats etc.) using commands like SYST:STAT?. Most of the commands immediately send back a response that I can read using the _serialPort.ReadLine().
However, the command SYST:STAT ON that turns on the system is one of the commands that takes about ten seconds. This is where the makers of the laser decided it's nice to send back a message that says: system ready. I can read this response asynchonously using the NewSerialDataRecieved event. In here, I read every line like this:
private void OnDataReceived(object sender, SerialDataEventArgs e)
{
_dataReceived += Encoding.ASCII.GetString(e.Data);
// Loop as long as there's full lines available
while (_dataReceived.Length > 0 && _dataReceived.Contains("\r\n"))
{
int delimiterIndex = _dataReceived.IndexOf("\r\n", StringComparison.Ordinal) + 2;
string line = _dataReceived.Substring(0, delimiterIndex); // Get first line from data
_dataReceived = _dataReceived.Substring(delimiterIndex, _dataReceived.Length - line.Length); // Remove first line from data
line = line.Substring(0, line.Length - 2);
TryParseSystemReadyResponse(line);
TryParseEnteringStandbyModeResponse(line);
TryParseTemperatureResponse(line);
OnResponseReceived?.Invoke(line);
}
}
The method reads the incoming data, stores it, and then parses the data line by line. This works perfectly for my asynchronous, well defined responses. Here's the catch: most of the responses are formatted like '0 0' or '0 1'. This means there's no way to parse them like that. This is why I read them directly after sending my command to the serial device, like this:
public void UpdateLaserState()
{
// Get the selected laser
_serialPortManager.SendCommand("LSR:NSEL?");
int selectedLaser = _serialPortManager.ReadIntegerResponse();
// Do stuff with the laser number
OnSystemStateChange?.Invoke();
}
ReadIntegerResponse is a method that does a ReadLine, strips the response of the preceding '0 ' and then parses the remaining string to int. Up to now, communication works as well as I would expect. Messages that can be synchronous are being read instantly and asynchronous messages can be parsed by my OnDataReceived method.
Here comes the problem. I need to read the temperature of the laser system about twice a second. My solution was to create a thread that reads the temperature, like this:
public Laser(){
_temperatureThread = new Thread(TemperatureTask);
_temperatureThread.Start();
_temperatureThreadRunning = true;
}
public void Dispose()
{
_temperatureThreadRunning = false;
_temperatureThread.Join();
}
private void TemperatureTask()
{
while (_temperatureThreadRunning)
{
this.UpdateTemperatures();
Thread.Sleep(TemperatureTaskSleep);
}
}
public void UpdateTemperatures()
{
_serialPortManager.SendCommand("SYST:TEMP?");
//string line = _serialPortManager.ReadResponse();
//TryParseTemperatureResponse(line);
}
This gives problems as UpdateTemperatures sends responses very often on a different thread. I resolved a lot of problems by implementing a lock. However, my responses often get mixed up. I think the following is happening:
Main thread Temperature thread
-----------------------------------------
Sends command |
| Sends command
Reads response |
| Reads response
This means the threads are reading eachothers responses. There is no good way to identify responses like '0 0' as belonging to a certain command.
Is there a way to prevent this from happening?
P.S. the ReadResponse methods of the _serialPortManager all look like this (except for parsing the response):
public string ReadResponse()
{
string response = SafeReadLine();
return StripResponse(response);
}
private string SafeReadLine()
{
lock (_serialPortLock)
{
string response = _serialPort.ReadLine();
return StripResponse(response);
}
}

blocking listen prevents disconnect

Overview of Problem:
I need to connect to an IRC Server. Once connected, the program will send a message to the channel, and a response will occur over multiple lines back. I need to read these lines and store in a variable for later use. A special character at the end of the message (]) will define the end of the message over multiple lines. Once we have received this character, the IRC session should disconnect and processing should continue.
Situation:
I am using the Smartirc4net library. Calling irc.Disconnect() takes about 40 seconds to disconnect the session. Once we've received the ] character, the session should be disconnected, Listen() should not be blocking, and the rest of the program should continue to run.
Research:
I have found this: smartirc4net listens forever, can't exit thread, and I think it might be the same issue, however, I am unsure of what I need to do to resolve the problem.
Code:
public class IrcCommunicator
{
public IrcClient irc = new IrcClient();
string data;
public string Data { get { return data; } }
// this method we will use to analyse queries (also known as private messages)
public void OnQueryMessage(object sender, IrcEventArgs e)
{
data += e.Data.Message;
if (e.Data.Message.Contains("]"))
{
irc.Disconnect(); //THIS TAKES 40 SECONDS!!!
}
}
public void RunCommand()
{
irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
string[] serverlist;
serverlist = new string[] { "127.0.0.1" };
int port = 6667;
string channel = "#test";
try
{
irc.Connect(serverlist, port);
}
catch (ConnectionException e)
{
// something went wrong, the reason will be shown
System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
}
try
{
// here we logon and register our nickname and so on
irc.Login("test", "test");
// join the channel
irc.RfcJoin(channel);
irc.SendMessage(SendType.Message, "test", "!query");
// here we tell the IRC API to go into a receive mode, all events
// will be triggered by _this_ thread (main thread in this case)
// Listen() blocks by default, you can also use ListenOnce() if you
// need that does one IRC operation and then returns, so you need then
// an own loop
irc.Listen();
// when Listen() returns our IRC session is over, to be sure we call
// disconnect manually
irc.Disconnect();
}
catch (Exception e)
{
// this should not happen by just in case we handle it nicely
System.Console.WriteLine("Error occurred! Message: " + e.Message);
System.Console.WriteLine("Exception: " + e.StackTrace);
}
}
}
IrcBot bot = new IrcBot();
bot.RunCommand();
ViewBag.IRC = bot.Data;
As you can see, once this
Thank you for your time to look at this code and read my problem description. If you have any thoughts, or other suggestions, please let me know.
Mike
I was able to successfully disconnect straight away by calling RfcQuit() within OnQueryMessage(), before irc.Disconnect();

How can I coordinate between COM port sends and receives?

I'm trying to refactor some ultra-complex legacy code that sends data from a handheld device to an app running on a PC, to which the handheld device is connected.
There is a "conversation" that goes on between the two apps that follows a protocol; the server (the app running on the PC) responds based on what the client tells it, and vice versa. Actually, the "conversation" can be seen about two thirds of the way down here.
Anyway, my problem is: how can I let the client wait for the server to respond without interrupting it, or thinking it's not going to respond and failing to continue? This is what I have right now:
public class FileXferLegacy : IFileXfer
{
private SerialPort cereal;
private String lastDataReceived;
private String receivedData;
. . .
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// This method will be called when there is data waiting in the port's buffer
try
{
receivedData += cereal.ReadLine();
lastDataReceived = receivedData;
ExceptionLoggingService.Instance.WriteLog(String.Format("Received {0} in FileXferLegacy.SendDataContentsAsXML", receivedData));
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
#region IFileFetchSend Members
. . .
public void SendDataContentsAsXML(string destinationPath, string data)
{
byte[] stuff;
ExceptionLoggingService.Instance.WriteLog("Reached
FileXferLegacy.SendDataContentsAsXML");
cereal.Open();
stuff = System.Text.UTF8Encoding.UTF8.GetBytes("PING" + "\n");
cereal.Write(stuff, 0, stuff.Length);
if (lastDataReceived.Contains("PING")) // Expecting "PING|ACKNOWLEDGE|"
{
stuff =
System.Text.UTF8Encoding.UTF8.GetBytes("LOGIN|foo|000003|LOC_HOST|PPP_PEER|1.4.0.42|bar" + "\n");
// TODO: replace this test data with dynamic data
cereal.Write(stuff, 0, stuff.Length);
}
if (lastDataReceived.Contains("JOIN|LEVEL")) // Expecting something like "JOIN|LEVEL|1
SETTING|ALT_ID|FALSE"
{
stuff = System.Text.UTF8Encoding.UTF8.GetBytes("HHTCOMMAND|GETHHTSUPDATE|");
cereal.Write(stuff, 0, stuff.Length);
}
. . .
String lastResponse = lastDataReceived; // Expecting something like
"RESULT|FILECOMPLETE|INV_000003_whatever(not identical to what was sent earlier!).XML"
// Parse out and do something with the filename ("INV_000003_whatever(not identical to
what was sent earlier!).XML" above)
}
As you can see, the client/handheld sends a string; it then reads "lastDataReceived" which is assigned in the DataReceived method. But what if there has been a delay, and "lastDataReceived" is null? What do I need to do to force a delay (without going to an extreme that would cause the app to appear slothlike in its slowness)? Or what is the way this should be done, if I'm totally off base?
A typical approach is to use a reader thread that pulls bytes off the port with blocking reads (though it can be done with async notification instead) and, once detecting that an entire message has been delivered, it either:
Puts them into a blocking queue (with consumer blocking on calls to dequeue until either a msg is added or a timeout reached
or
Notifies a listener with an event that contains the message.
Which of those two depends a lot on the consumer of those messages. Your code above would benefit from #1, though if the consumer is the UI thread then you should look at #2.
The protocol seems to be half-duplex so rewriting it with synchronous calls to Write/Readline seems to be the simplest way to handle it.

C# reinvoke current method

Not quite sure how to do this or if it even is a proper way to program c#. Maybe I need to rethink what I am trying to do, but I need some help.
I have a wpf application that starts/stops a service and also uses a named pipe to open a port and communicate with the service. So when the service needs to it can send a message to the app. I started a new thread to invoke a Wait() method that sits at namedPipeServerStream.WaitForConnection(). This works fine, but when the service is stopped I send a message to the app so it breaks the WaitForConnection, however I dont want to kill this thread, I want to reinvoke the same method and wait in a loop until the service starts again. Not sure of the best way to do this.
The code I have so far is below.
void Wait()
{
while (!ServiceControl.ServiceRunning)
{
Thread.Sleep(250);
if (exitProgram == true)
{
break;
}
}
while (ServiceControl.ServiceRunning)
{
try
{
NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream("pipeName");
namedPipeServerStream.WaitForConnection();
byte[] buffer = new byte[255];
namedPipeServerStream.Read(buffer, 0, 255);
string request = ASCIIEncoding.ASCII.GetString(buffer);
if (request != null)
{
if (request == "pipeExit")
{
Wait(); //Reinvoke Wait if svc calls to exit
}
else
{
//Do work on message
}
}
namedPipeServerStream.Close();
}
catch (Exception){}
}
if (_opener.exitProgram == true)
{
Application.Current.Dispatcher.InvokeShutdown();
}
Why don't you put a while(!opener.exitProgram) around your entire Wait implementation? That way you'll get back to the start once the pipe is closed.

Categories