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.
Related
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.
Im trying to setup a named pipes connection between a server-software and a client.
This is my server code:
class Program
{
private static NamedPipeServerStream server = new NamedPipeServerStream("p", PipeDirection.InOut);
static void Main(string[] args)
{
Action<NamedPipeServerStream> a = callBack;
a.BeginInvoke(server, ar => { }, null);
}
private static void callBack(NamedPipeServerStream pipe)
{
pipe.WaitForConnection();
var line = "";
while (line != "exit")
{
try
{
StreamReader reader = new StreamReader(pipe);
while (line != "exit")
{
line = reader.ReadLine();
switch (line)
{
default:
foo();
break;
}
}
break;
}
catch (IOException)
{
pipe.Disconnect();
continue;
}
}
}
}
But when I try to run this application it exits directly after the start.
I have used the debugger to reach the WaitForConnection-line and then it exits without an error or an exception. And there is nothing running but the server.
It quits without getting handled by the catch-part. Am I missing anything?
The execution is blocked on WaitForConnection and will not continue until a NamedPipeClientStream object establishes a connection to the NamedPipeServerStream object.
Please have a look here (The example should help you out): https://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream(v=vs.110).aspx
EDIT: I misunderstood the problem and originally thought that the question had to do with the execution blocking from the WaitForConnection method. The code below is the addition to the actual quesiton as well as my explanation.
The problem is the way you invoke your action. As you are calling BeginInvoke it is invoked asynchronously, on a threadpool thread. Therefor you need to check if the action has finished or not otherwise the main thread keeps running and reaches the end. I have updated my answer on how you can do this very easily
Hopefully this code helps you understand why it exists! :)
Action<NamedPipeServerStream> a = callBack;
var result = a.BeginInvoke(server,ar => { },null);
while (!result.IsCompleted)
{
}
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.
I have two self hosted services running on the same network. The first is sampling an excel sheet (or other sources, but for the moment this is the one I'm using to test) and sending updates to a subscribed client.
The second connects as a client to instances of the first client, optionally evaluates some formula on these inputs and the broadcasts the originals or the results as updates to a subscribed client in the same manner as the first. All of this is happening over a tcp binding.
My problem is occuring when the second service attempts to subscribe to two of the first service's feeds at once, as it would do if a new calculation is using two or more for the first time. I keep getting TimeoutExceptions which appear to be occuring when the second feed is subscribed to. I put a breakpoint in the called method on the first server and stepping through it, it is able to fully complete and return true back up the call stack, which indicates that the problem might be some annoying intricacy of WCF
The first service is running on port 8081 and this is the method that gets called:
public virtual bool Subscribe(int fid)
{
try
{
if (fid > -1 && _fieldNames.LeftContains(fid))
{
String sessionID = OperationContext.Current.SessionId;
Action<Object, IUpdate> toSub = MakeSend(OperationContext.Current.GetCallbackChannel<ISubClient>(), sessionID);//Make a callback to the client's callback method to send the updates
if (!_callbackList.ContainsKey(fid))
_callbackList.Add(fid, new Dictionary<String, Action<Object, IUpdate>>());
_callbackList[fid][sessionID] = toSub;//add the callback method to the list of callback methods to call when this feed is updated
String field = GetItem(fid);//get the current stored value of that field
CheckChanged(fid, field);//add or update field, usually returns a bool if the value has changed but also updates the last value reference, used here to ensure there is a value to send
FireOne(toSub, this, MakeUpdate(fid, field));//sends an update so the subscribing service will have a first value
return true;
}
return false;
}
catch (Exception e)
{
Log(e);//report any errors before returning a failure
return false;
}
}
The second service is running on port 8082 and is failing in this method:
public int AddCalculation(string name, string input)
{
try
{
Calculation calc;
try
{
calc = new Calculation(_fieldNames, input, name);//Perform slow creation before locking - better wasted one thread than several blocked ones
}
catch (FormatException e)
{
throw Fault.MakeCalculationFault(e.Message);
}
lock (_calculations)
{
int id = nextID();
foreach (int fid in calc.Dependencies)
{
if (!_calculations.ContainsKey(fid))
{
lock (_fieldTracker)
{
DataRow row = _fieldTracker.Rows.Find(fid);
int uses = (int)(row[Uses]) + 1;//update uses of that feed
try
{
if (uses == 1){//if this is the first use of this field
SubServiceClient service = _services[(int)row[ServiceID]];//get the stored connection (as client) to that service
service.Subscribe((int)row[ServiceField]);//Failing here, but only on second call and not if subscribed to each seperately
}
}
catch (TimeoutException e)
{
Log(e);
throw Fault.MakeOperationFault(FaultType.NoItemFound, "Service could not be found");//can't be caught, if this timed out then outer connection timed out
}
_fieldTracker.Rows.Find(fid)[Uses] = uses;
}
}
}
return id;
}
}
catch (FormatException f)
{
Log(f.Message);
throw Fault.MakeOperationFault(FaultType.InvalidInput, f.Message);
}
}
The ports these are on could change but are never shared. The tcp binding used is set up in code with these settings:
_tcpbinding = new NetTcpBinding();
_tcpbinding.PortSharingEnabled = false;
_tcpbinding.Security.Mode = SecurityMode.None;
This is in a common library to ensure they both have the same set up, which is also a reason why it is declared in code.
I have already tried altering the Service Throttling Behavior for more concurrent calls but that didn't work. It's commented out for now since it didn't work but for reference here's what I tried:
ServiceThrottlingBehavior stb = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 400,
MaxConcurrentSessions = 400,
MaxConcurrentInstances = 400
};
host.Description.Behaviors.RemoveAll<ServiceThrottlingBehavior>();
host.Description.Behaviors.Add(stb);
Has anyone had similar issues of methods working correctly but still timing out when sending back to the caller?
This was a difficult problem and from everything I could tell, it is an intricacy of WCF. It cannot handle one connection being reused very quickly in a loop.
It seems to lock up the socket connection, though trying to add GC.Collect() didn't free up whatever resources it was contesting.
In the end the only way I found to work was to create another connection to the same endpoint for each concurrent request and perform them on separate threads. Might not be the cleanest way but it was all that worked.
Something that might come in handy is that I used the svc trace viewer to monitor the WCF calls to try and track the problem, I found out how to use it from this article: http://www.codeproject.com/Articles/17258/Debugging-WCF-Apps
I am working on a multiplayer game, using the lidgren library for networking.
I am currently having issues with a my function that reads messages sent from my server.
The function looks like this:
public class Client
{
/* code omitted */
public void ReadMessage()
{
//Read Messages
while (running)
{
Debug.Log("InREAD");
//wClient is a NetClient (lidgren library)
NetIncomingMessage msg;
while ((msg = wClient.ReadMessage()) != null)
{
switch (msg.MessageType)
{
case NetIncomingMessageType.Data:
if (msg.ReadString().Contains("Position"))
{
Debug.Log("Hej");
/*string temp = msg.ReadString();
string[] Parts = temp.Split(" ");
int x = int.Parse(Parts [1]);
int y = int.Parse(Parts [2]);
int z = int.Parse(Parts [3]);*/
//set player position to xyz values below
} else if (msg.ReadString().Contains("Instantiate"))
{
Debug.Log("Instantiate");
/* string temp = msg.ReadString();
string[] Parts = temp.Split(" ");*/
}
break;
}
}
}
}
}
as you can see, there is a while-loop that runs when the bool running is true (and yes I am setting it as true when declaring.).
Now, in my GUI class where the button for connecting is etc, I have a function call to OnApplicationQuit which looks like this:
void OnApplicationQuit()
{
client.running = false;
client.Disconnect();
Debug.Log(client.running);
Debug.Log("Bye");
}
However, the change of running doesn't reach the thread (I believe the thread is running on a cached version of the variable?). So my question is, how do i make the while-loop stop when the program is closed? (Ive tried calling on the .Abort() function on the thread in the OnApplicationQuit(), but it doesn't work either.
Also, i know its not very efficient to send strings over a network unless you need to (so no need telling me about that!)
Just guessing (since I do not know library lidgren): isn't it possible that you're thread is stuck in call wClient.ReadMessage() just because you are not receiving any message from the client? If wClient.ReadMessage() is a blocking call then the resulting behaviour would be the one you described.
Furthermore: even calling Thread.Abort() won't work because the thread is in a sleep state (since it is waiting for something coming from the network connection): the thread will be aborted as soon as your wClient.ReadMessage() returns. Looking MSDN here it tells that "If Abort is called on a managed thread while it is executing unmanaged code, a ThreadAbortException is not thrown until the thread returns to managed code" and this exactly your situation assuming that ReadMessage() at some point will perform a system call just to wait for some data coming from the underlying socket.
You must call client.Shutdown().