C#/WPF/Unity namepipes communication sends messages just in one direction - c#

I got stuck in solving a problem in my current project. I'm coding a simulation in WPF/C# and included a Unity-Application in the window using the window-handles/hwnd pretty much like "Programmer" did in this answer. He also suggested namedpipes for the communication.
But the communication just works in one way - The server (WPF-App) is able to send messages to the client (the embedded Unity-App). If I try it the other way around, the whole Unity-App hungs up and stops working. As far as I was able to figure it out, as soon as I flush the writer or add the AutoFlush and then write something Unity gets stuck.
It is interesting, that the InBufferSize of the server is 0. Might this be the Problem?
This is my C#-Script in Unity assigned to a GameObject:
public class pipeCommunicationScript : MonoBehaviour
{
NamedPipeClientStream client;
public GameObject console;
static Text consoleText;
StreamReader reader;
StreamWriter writer;
int counter = 0;
static bool _threadRunning;
Thread _thread;
void Start()
{
consoleText = console.GetComponent<Text>();
consoleText.text = "trying to set up client";
_thread = new Thread(StartClient);
_thread.Start();
}
void StartClient()
{
_threadRunning = true;
//Client
consoleText.text = "Attempting to connect to pipe...";
client = new NamedPipeClientStream(".","UnitySimulationPipe", PipeDirection.InOut);
if (!client.IsConnected) { client.Connect(); }
consoleText.text = "Connected to pipe.";
writer = new StreamWriter(client);
reader = new StreamReader(client);
writer.AutoFlush = true;
InvokeRepeating("sendThroughPipe", 5.5f, 5.5f);
while (_threadRunning)
{
consoleText.text = "IN:" + reader.ReadLine();
}
_threadRunning = false;
}
void sendThroughPipe()
{
try
{
client.WaitForPipeDrain();
writer.WriteLine("test" + counter);
}
catch(Exception e)
{
consoleText.text = "Exception while sending: " + e;
}
consoleText.text = "OUT: test" + counter;
counter++;
}
void OnDisable()
{
if (_threadRunning)
{
_threadRunning = false;
_thread.Join();
}
}
}
And this my Server-Script:
void StartServer()
{
Task.Factory.StartNew(() =>
{
Console.WriteLine("Connection initialisation started");
var server = new NamedPipeServerStream("UnitySimulationPipe", PipeDirection.InOut);
server.WaitForConnection();
while (!server.IsConnected)
{
Console.WriteLine("Connection not initialized");
server.WaitForConnection();
}
Console.WriteLine("Connection initialized");
reader = new StreamReader(server);
writer = new StreamWriter(server);
writer.AutoFlush = true;
writer.WriteLine("startConnection");
printOnStatusBar("OUT: startConnection");
connected = true;
Console.WriteLine("Current pipe readable: " + server.CanRead);
Console.WriteLine("Pipe InBufferSize: " + server.InBufferSize);
while (true)
{
Console.WriteLine("start while again");
if (reader.Peek() > 0)
{
var l = reader.ReadLine();
Console.WriteLine(reader.ReadLine());
Console.WriteLine("read finished");
server.WaitForPipeDrain();
}
Thread.Sleep(500);
}
});
}

The most probable answer is, in fact, what you mentionned (bufferSize).
You should check for the initialyzers parameters of every object you use.
Don't worry, I'm sure you'll find the answer just by searching there. I used to create such code in the same way, it should work well.

Okay, I changed my initilisation of the server-object to (explanation of different parameters here):
var server = new NamedPipeServerStream("UnitySimulationPipe", PipeDirection.InOut, 1, 0, 0, 1024, 1024);
But I personally think, that this was just a minor mistake. The mainreason why my code didn't worked was, that I missed to call
server.WaitForPipeDrain();
after
writer.WriteLine("startConnection");
printOnStatusBar("OUT: startConnection");
in my server-code.

Related

NetMQ Polling a rep socket with a timeout in a loop

I'm trying to port my code from an obsolete library called CastleMQ to NetMQ but I'm running into some problems.
I prefer to using polling with a timeout, for reliability - I just found that it worked best for me from trial and error compared to just sitting blocking the port indefinitely.
here is my CastleMQ code
public int ZeroPort;
private void ThreadProc()
{
var ctx = new Context();
try {
using (var repSocket = ctx.CreateSocket(SocketType.Rep))
{
string bindAddress = "tcp://*:"+ZeroPort;
repSocket.Bind(bindAddress);
print2("*** BINDING on {0} ***", bindAddress);
bool quit = false;
while (!quit) {
try {
var polling = new Polling(PollingEvents.RecvReady, repSocket);
polling.RecvReady += (socket) =>
{ // using socket.Recv() here is guaranted to return stuff
var msg = socket.Recv();
var msgStr = Encoding.UTF8.GetString(msg);
print2("[REP:{0}] {1}", bindAddress, msgStr);
switch (msgStr) {
case "positions": {
StringBuilder csv = new StringBuilder();
print2("csv: {0}", csv.ToString());
socket.Send(csv.ToString());
break;
}
default: {
socket.Send("Unrecognized Command: " + msgStr);
break;
}
}
};
polling.Poll(POLL_TIMEOUT_MS); // this returns once some socket event happens
} catch (Exception e) {
if (e is ThreadAbortException) {
quit = true;
print2("\n*** EXITED ***");
} else print2(e.ToString());
}
}
}
} catch (Exception e) {
print2(e.ToString());
} finally {
ctx.Dispose();
}
}
here is what I tried to do and then got lost with NetMQ
private void ThreadProc()
{
try {
string bindAddress = "#tcp://*:" + ZeroPort;
print2("*** BINDING on {0} ***", bindAddress);
using (var repSocket = new ResponseSocket(bindAddress))
using (var poller = new NetMQPoller { repSocket })
{
// bool quit = false;
// while (!quit)
// these event will be raised by the Poller
repSocket.ReceiveReady += (s, a) =>
{
// receive won't block as a message is ready
string msg = a.Socket.ReceiveString(); // defeinition for ReceiveString() can't be found
// send a response
a.Socket.Send("Response"); // it doesn't like "Response", do I need to wrap it in some object?
I'm especially confused as how to add a timeout so I can poll with a timeout in a loop the way my CastleMQ code does.
Any pointers would be much appreciated, thanks

Arduino - Unity Serial Communication

I am going to make a basic communication between Unity and Arduino. The problem that i have is that when i start sending data from unity to arduino, it's working properly. But when i start reading serial from Arduino. I got Access denied error !!!
After i read more about the issue, i can't find the real reason for that. I need to understand why something like that happens.
using UnityEngine;
using System.Collections;
using System;
using System.IO.Ports;
using System.Text;
using System.Threading;
public class Program : MonoBehaviour {
public SerialPort mySerialPort = new SerialPort("COM7", 9600);
public volatile float speed=0;
volatile bool isPassed = true;
GameObject cube ;
public GUIStyle style ;
// int readInterval = 4;
// int alreadyCounter = 0;
// string rxString = "";
void Start () {
isPassed = true;
speed = 0;
//mySerialPort.ReadTimeout = 25;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.DtrEnable = true;
cube = GameObject.FindGameObjectWithTag ("cube");
/*foreach(string str in SerialPort.GetPortNames())
{
Debug.Log(string.Format("Existing COM port: {0}", str));
};
*/
try{
mySerialPort.Open();
}catch(Exception ex)
{
print("Start Error Opening : " + ex.ToString());
}
/*
new Thread (delegate() {
updateSpeed();
}).Start();
*/
}
void OnGUI(){
GUI.Box (new Rect(100,100,100,100),"Speed : " + speed , style);
}
// Update is called once per frame
void Update () {
cube.transform.Rotate(Vector3.up * speed *Time.deltaTime);
if (mySerialPort.IsOpen) {
speed = float.Parse (mySerialPort.ReadLine ());
} else {
if(mySerialPort!= null)
{
mySerialPort.Close();
mySerialPort.Open();
}
}
/*if (isPassed == true) {
new Thread(delegate() {
if(mySerialPort.IsOpen) {
updateSpeed();
isPassed = false;
} else {
try {
mySerialPort.Close();
mySerialPort.Open();
} catch (Exception ex) {
print("Update Error Opening : " + ex.ToString());
}
}
}).Start();
}*/
}
public void updateSpeed()
{
while (true) {
speed = float.Parse(mySerialPort.ReadLine ());
print ("Speed = " + speed);
Thread.Sleep (60);
mySerialPort.BaseStream.Flush ();
}
}
void OnDestroy ()
{
mySerialPort.Close();
}
}
When you call Close the SerialPort is disposed as you can read on the MSDN page. It also suggest to not try to reopen it immediately after closing it as it might not be closed yet.
Also since the SerialPort will be disposed you would have to create a new one. I would suggest to not closing and opening the port in Update when it's not open yet. Open it once in Start and just close it in OnDestroy.
edit
It seems you don't have to create a new SerialPort when you called Close on it. So it can be reused after "waiting some time".
Update:
Now, you can use Microsoft .net open source framework instead of the unity default, the serial communication works like a charm there.

Update main thread from worker without a dispatcher

This have probably been asked before, but I cant find the right answer.
I have a dll that runs a pipe in it's own thread. I use that dll in a Unity project, but the messages I push to Unity end up as exception, due to I don't call them from the main thread. So I need some help implementing this right. Here's how I start the background worker:
var worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
client.Connect();
while (_isWorkerRunning)
{
using (var sr = new StreamReader(client))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
// TODO send message to Unity in main thread
}
}
if (!client.IsConnected)
{
client.Connect();
}
}
client.Flush();
client.Close();
client.Dispose();
};
worker.RunWorkerAsync();
My pipe client runs in a thread, I have a public event that fires the messages to Unity. But i need to ensure the messages is dispatched. And I am not sure how to do this the right way?
I found a simple solution, where I use a shared buffer across the threads. So my pipe look like this:
private void PipeClientWorker()
{
//Client
var client = new NamedPipeClientStream(".", "kinect-pipe", PipeDirection.In);
client.Connect();
while (_isWorkerRunning)
{
using (var sr = new StreamReader(client))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
// TODO figure out how to do this in the right thread
if (KinectHandler != null)
{
KinectHandler.BeginInvoke(temp, null, null);
}
}
}
if (!client.IsConnected)
{
client.Connect();
}
}
client.Flush();
client.Close();
}
And I start it normally:
var thread = new Thread(PipeClientWorker) {Name = "Pipe Worker Thread", IsBackground = true};
thread.Start();
In Unity I've created a KinectController that puts the messages in a stack, and in the Update loop pops them to a single LastMessage string:
public string LastMessage;
private KinectReader _kinectReader;
private volatile Stack<string> _messageStack;
// Use this for initialization
void Start ()
{
_messageStack = new Stack<string>();
LastMessage = "";
// init Kinect Reader
_kinectReader = new KinectReader();
_kinectReader.StartPipeReader();
_kinectReader.KinectHandler += _kinectReader_KinectHandler;
}
void _kinectReader_KinectHandler(string message)
{
_messageStack.Push(message);
}
// Update is called once per frame
void Update ()
{
// Update Last message
while (_messageStack.Any())
{
LastMessage = _messageStack.Pop();
Debug.Log(LastMessage);
}
}
void OnApplicationQuit()
{
Debug.Log("Stoping the pipe client");
_kinectReader.Stop();
Debug.Log("Qutting application");
}
If anyone have similar issues or have solved it different I would like to discuss the solution :)
Try Thread Ninja. With it you can run background jobs in a coroutine style.

Label won't change color until after code is finished executing

It's a lot of irrelevant code to look through.. but pretty much it sends a packet and listens for a packet in return
if i comment the part out where it calls the ReceiveAuthPacket() method at the end of sending a packet, it will work and the label will turn blue.. but otherwise it will never activate turning the label blue and will instead turn the label red or green (depending on the returned packet).
basically im just using the label as an indicator of the status.. and no matter what i try i can't get it to turn blue because it seems to be waiting for all the code to be finished executing and it just won't work..
i even tried using data triggers in WPF and it still won't work.
any work arounds? i just don't get it..
private readonly UdpMessageAuthentication _msgAuth;
private void Button_Authenticate_OnClick(object sender, RoutedEventArgs e)
{
Label_Authentication.Content = "Attempting Authentication";
Label_Authentication.Foreground = new SolidColorBrush(Colors.Blue);
_msgAuth.SendAuthPacket(IPAddress.Parse(TextBox_IP.Text), TextBox_ClientID.Text);
}
public void SendAuthPacket(IPAddress ip, string userID)
{
_ip = ip;
_userID = userID;
if (_udpClient.Client == null)
_udpClient = new UdpClient();
//GSISClockRegRequest,<Client Id>,,1
string msg = string.Format("GSISClockRegRequest,{0},,1", _userID);
byte[] sendBytes = Encoding.ASCII.GetBytes(msg);
bool sent = false;
try
{
_label.Content = "Attempting Authentication";
_label.Foreground = new SolidColorBrush(Colors.Blue);
while (_label.Content != "Attempting Authentication")
{
//loop
}
_udpClient.Connect(_ip, 5001);
_udpClient.Send(sendBytes, sendBytes.Length);
Console.WriteLine("Sending {0} bytes. Message: {1}", sendBytes.Length, msg);
sent = true;
}
catch (Exception)
{
Console.WriteLine("UDP Auth Packet Failed to Send");
}
_udpClient.Close();
if (sent)
ReceiveAuthPacket(); //IF I COMMENT THIS OUT IT'LL WORK
}
private void ReceiveAuthPacket()
{
IPEndPoint e = new IPEndPoint(IPAddress.Any, 5001);
UdpClient u = new UdpClient(e);
u.Client.ReceiveTimeout = 3000;
Console.WriteLine("Listening for Messages: ");
try
{
Byte[] receiveBytes = u.Receive(ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Received: {0}", receiveString);
string errMsg = "";
if (AuthMessageParser.ParseMessage(receiveString, ref errMsg))
{
_label.Content = "Authentication Successful!";
_label.Foreground = new SolidColorBrush(Colors.Green);
}
else
{
_label.Content = "Authentication Unsuccessful: " + errMsg;
_label.Foreground = new SolidColorBrush(Colors.Red);
}
}
catch (Exception)
{
_label.Content = "Authentication Unsuccessful";
_label.Foreground = new SolidColorBrush(Colors.Red);
Console.WriteLine("UDP Auth Packet was NOT Received.");
}
u.Close();
}
Your UI thread is blocked by calls to things like _udpClient.Connect() and _udpClient.Send() (and the receives, too)
A workaround would be to leverage the task parallel library and perform communications asynchronously to avoid blocking the UI thread.
It will manage threads for you as long as you define tasks properly. Holler if you need an example.
protected void SomeButton_Click(Object sender, EventArgs e)
{
// Task off the work and do not wait, no blocking here.
Task.Run(PerformConnection);
}
private async Task PerformConnection()
{
// This method acts the way a thread should. We await the result of async comms.
// This will not block the UI but also may or may not run on its own thread.
// You don't need to care about the threading much.
var conn = await ListenerOrSomething.AwaitConnectionsAsync( /* ... */ );
// Now you have your result because it awaited.
using(var newClient = conn.Client())
{
var buffer = new byte[];
var recv = await newClient.ReceiveAsyncOrSomething(out buffer);
// Data received is not zero, process it or return
if(recv > 0)
newClient.Response = await ProcessRequest(buffer);
else
return;
}
}

Why does my streamreader and writer suddenly stop working?

Ok, so I'm attempting to create a simple Chat application over TCP/IP for a group of friends of mine who play DnD online. Eventually I want to add more features, but for now I just want the chat to work!!
Here is the code I have for the Main Server
class MainServer
{
IPAddress m_address = IPAddress.Parse("127.0.0.1");
Int32 m_port = 5550;
public static Hashtable userNicknames = new Hashtable(50);
public static Hashtable connectionToNick = new Hashtable(50);
public MainServer()
{
TcpListener listener = new TcpListener(m_address, m_port);
Thread listenThread = new Thread(new ParameterizedThreadStart(StartListening));
listenThread.Start(listener);
Console.WriteLine("Listening for incoming connection requests...");
}
private void StartListening(Object listener)
{
TcpListener server = (TcpListener)listener;
ClientCommCenter commC;
server.Start();
while (true)
{
if (server.Pending())
{
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client has connected...");
commC = new ClientCommCenter(client);
}
}
}
public static void SendSystemMessage(string msg)
{
StreamWriter writer;
TcpClient[] connectedClients = new TcpClient[MainServer.userNicknames.Count];
MainServer.userNicknames.Values.CopyTo(connectedClients, 0);
for (int ii = 0; ii < connectedClients.Length; ii++)
{
try
{
if (msg.Trim().Equals(String.Empty))
continue;
writer = new StreamWriter(connectedClients[ii].GetStream());
writer.WriteLine("Message from server: " + msg);
writer.Flush();
writer = null;
}
catch (Exception e)
{
MainServer.userNicknames.Remove(MainServer.connectionToNick[connectedClients[ii]]);
MainServer.connectionToNick.Remove(connectedClients[ii]);
}
}
}
public static void SendMessageToAll(string nickname, string msg)
{
StreamWriter writer;
TcpClient[] connectedClients = new TcpClient[MainServer.userNicknames.Count];
MainServer.userNicknames.Values.CopyTo(connectedClients, 0);
for (int ii = 0; ii < connectedClients.Length; ii++)
{
try
{
if (msg.Trim().Equals(String.Empty))
continue;
writer = new StreamWriter(connectedClients[ii].GetStream());
writer.WriteLine(nickname + ": " + msg);
writer.Flush();
writer = null;
}
catch (Exception e)
{
String user = (string)MainServer.connectionToNick[connectedClients[ii]];
SendSystemMessage("ATTENTION: " + user + " has disconnected from chat");
MainServer.userNicknames.Remove(user);
MainServer.connectionToNick.Remove(connectedClients[ii]);
}
}
}
}
Here is the main communication class, used separately by each client
class ClientCommCenter
{
TcpClient m_client;
StreamReader m_reader;
StreamWriter m_writer;
String m_nickname;
public ClientCommCenter(TcpClient client)
{
m_client = client;
Thread chatThread = new Thread(new ThreadStart(StartChat));
chatThread.Start();
}
private String GetNick()
{
m_writer.WriteLine("Enter a nickname to begin.");
m_writer.Flush();
return m_reader.ReadLine();
}
private void StartChat()
{
m_reader = new StreamReader(m_client.GetStream());
m_writer = new StreamWriter(m_client.GetStream());
m_writer.WriteLine("Connected to DnD Chat!!");
m_nickname = GetNick();
while (MainServer.userNicknames.Contains(m_nickname))
{
m_writer.WriteLine("ERROR!!! Username already in use");
m_nickname = GetNick();
}
MainServer.userNicknames.Add(m_nickname, m_client);
MainServer.connectionToNick.Add(m_client, m_nickname);
MainServer.SendSystemMessage("****** " + m_nickname + " ****** has joined the chat!");
m_writer.WriteLine("Now connected....");
m_writer.Flush();
Thread startChatting = new Thread(new ThreadStart(runChat));
startChatting.Start();
}
private void runChat()
{
try
{
String clientMessage = String.Empty;
while(true){
clientMessage = m_reader.ReadLine();
MainServer.SendMessageToAll(m_nickname, clientMessage);
}
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
}
And finally, here is the code for the Client class:
public partial class MainForm : Form
{
[DllImport("kernel32.dll")]
private static extern void ExitProcess(int a);
TcpClient client;
StreamReader m_reader;
StreamWriter m_writer;
public MainForm()
{
InitializeComponent();
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = false;
Application.Exit();
if (m_reader != null)
{
m_reader.Dispose();
}
ExitProcess(0);
}
private void MainForm_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
SendChat();
}
}
private void SendChat()
{
TextBox txtChat = (TextBox)chatEntry;
if (chatEntry.Lines.Length >= 1)
{
m_writer.WriteLine(txtChat.Text);
m_writer.Flush();
chatEntry.Text = String.Empty;
chatEntry.Lines = null;
}
}
private void RunChat()
{
StreamReader reader = new StreamReader(client.GetStream());
while (true)
{
Application.DoEvents();
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker( delegate{
RunChat();
}));
}
if (reader.Peek() > 0)
{
chatDisplay.AppendText(reader.ReadLine() + "\r\n");
chatDisplay.SelectionStart = chatDisplay.Text.Length;
}
}
}
private void toolstripConnectButton_Click(object sender, EventArgs e)
{
client = new TcpClient("127.0.0.1", 5550);
m_writer = new StreamWriter(client.GetStream());
m_reader = new StreamReader(client.GetStream());
Thread chatThread = new Thread(new ThreadStart(RunChat));
chatThread.Start();
while (true)
{
Application.DoEvents();
}
}
private void sendButton_Click(object sender, EventArgs e)
{
SendChat();
}
}
The problem that I am having with the above code is this: I can connect to the running server perfectly fine, and I am correctly prompted by the server that I have connected, and it then prompts me for a nickname.
I type the nickname into the text box and press send. After this occurs however, I stop receiving messages from the server all together. Literally nothing. I can even spam the connect button and it constantly shows up with the same two messages:
"Connected"
"Enter a nickname"
I have been trying to figure this out for close to 5 hours now, and I simply have no idea what is going on. I have a feeling it is something incredibly simple, as the solution is ALWAYS simple.
So, generous people of SO, can you figure out my problem? Why does my streamreader and streamwriter suddenly stop working?!?!?!
Two things:
First, skip the if (reader.Peek() > 0). Just call reader.ReadLine(); this will block until you have a line available. I am not sure why, but even after sending the message, Peek is returning -1, but ReadLine returns a line at that point, fixing the problem. Anyway, spinning around on Application.DoEvents() is not helping matters.
(Similarly, you can skip if (server.Pending())).
Second, your use of Invoke is faulty; you should not be "Invoking" RunChat() because that is the method that repeatedly polls the stream for new data. This means you will run the entire method on the UI thread, which is precisely what you want to avoid. The UI is busy pumping the Windows message queue. You should "Invoke" only the code that modifies the control's properties.
(I suspect that is why you found it necessary to use Application.DoEvents() anyway. You shouldn't need it if you are handling your threading correctly.)
(Also, the first thing you should do is to check InvokeRequired. As your method is now, you're creating a StreamReader that you can never use. There are other places where you do that, but that's off topic.)
Here are two suggestions:
private void RunChat()
{
StreamReader reader = new StreamReader(client.GetStream());
Delegate invoker = new Action<string>(AppendChatText);
while (true)
Invoke(invoker, reader.ReadLine());
}
or, to use the more classic "invoke" pattern:
private void RunChat()
{
StreamReader reader = new StreamReader(client.GetStream());
while (true)
AppendChatText(reader.ReadLine());
}
private void AppendChatText(string text)
{
if (this.InvokeRequired)
{
this.Invoke((Action<string>)AppendChatText, text);
return;
}
chatDisplay.AppendText(text + "\r\n");
chatDisplay.SelectionStart = chatDisplay.Text.Length;
}
The first has the advantage of creating only one Delegate object; the second creates a new one each time.
Finally, this is a very C# 1.2 approach to the problem. A more up-to-date approach would use async/await to avoid creating all those threads (not to mention System.Collections.Generic.Dictionary<,> instead of HashTable).

Categories

Resources