Hi
I am trying to implement named pipes into my game to pass data to and from another application.
Game Code
using UnityEngine;
using System.Collections;
using System.IO.Pipes;
using System.Text;
public class PipeWork : MonoBehaviour
{
NamedPipeClientStream clientStream;
// Use this for initialization
void Start ()
{
clientStream = new NamedPipeClientStream ("mypipe");
clientStream.Connect (60);
byte[] buffer = ASCIIEncoding.ASCII.GetBytes ("Robot Connected /n");
Debug.Log ("connected");
clientStream.Write (buffer, 0, buffer.Length);
}
int count = 0;
// Update is called once per frame
void Update ()
{
//clientStream.Flush ();
byte[] buffer = ASCIIEncoding.ASCII.GetBytes ("done");
//byte[] buffer = "SENDING...".to;
Debug.Log (count.ToString ());
count++;
if(count > 5 )
{
clientStream.Write (buffer, 0, buffer.Length);
count = 0;
}
}
}
Receiver
using System;
using System.Text;
using System.IO.Pipes;
namespace PipeSample
{
class Program
{
static void Main(string[] args)
{
//This is a server pipe named mypipe
//The only thing it does is echo whatever it has received to the console
Console.WriteLine("Waiting for connection on named pipe mypipe");
while (true)
{
System.IO.Pipes.NamedPipeServerStream namedPipeServerStream = new NamedPipeServerStream("mypipe");
namedPipeServerStream.WaitForConnection();
byte[] buffer = new byte[255];
namedPipeServerStream.Read(buffer, 0, 255);
string request = ASCIIEncoding.ASCII.GetString(buffer);
Console.WriteLine(request);
request = request.Trim('\0');
if (request.ToLower() == "close")
break;
namedPipeServerStream.Close();
}
}
}
}
when both are run, the receiver runs ok. But when the game is run, it only seems to send the data, all at once, when the game is closed. If I add a flush command in, I just get errors:
IOException: Win32 IO returned 232. Path: C:\Users\Jay\Documents\ROBOT\[Unknown]
System.IO.FileStream.FlushBuffer (System.IO.Stream st) (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.IO/FileStream.cs:1040)
System.IO.FileStream.FlushBuffer () (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.IO/FileStream.cs:1054)
System.IO.FileStream.Flush () (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.IO/FileStream.cs:859)
System.IO.Pipes.PipeStream.Flush ()
PipeWork.Update () (at Assets/PipeWork.cs:23)
Can anyone advise?
1 Like
Don’t know if anybody is still interested in a solution, but the problem is as far as I know that you have to always open and close a connection at every call to the pipe. I tested following code and it works:
using UnityEngine;
using System.Collections;
using System.IO.Pipes;
using System.Text;
public class PipeWork : MonoBehaviour
{
NamedPipeClientStream clientStream;
// Use this for initialization
void Start ()
{
clientStream = new NamedPipeClientStream ("mypipe");
clientStream.Connect (60);
byte[] buffer = ASCIIEncoding.ASCII.GetBytes ("Robot Connected /n");
Debug.Log ("connected");
clientStream.Write (buffer, 0, buffer.Length);
clientStream.Flush();
clientStream.Dispose();
clientStream.Close();
}
int count = 0;
void SendToPipe(){
byte[] buffer = ASCIIEncoding.ASCII.GetBytes (" done");
clientStream = new NamedPipeClientStream ("mypipe");
clientStream.Connect (TimeSpan.MaxValue.Seconds);
clientStream.WaitForPipeDrain();
clientStream.Write (buffer, 0, buffer.Length);
clientStream.Flush ();
clientStream.Dispose();
clientStream.Close();
}
// Update is called once per frame
void Update ()
{
Debug.Log (count.ToString ());
count++;
if(count > 5 )
{
SendToPipe();
count = 0;
}
}
}
1 Like
@sloopidoopi
you forgate to add [using System;]
Doesn’t work for me my Unity just crashes.
Spent yesterday trying to solve this problem as a way of getting 64-bit Unity to make use of an old out-of-production 32-bit DLL.
Found that Named Pipes work without problem in Unity 2017.01, if you set the “Scripting Runtime Version” in the player settings to “Experimental (.NET 4.6 Equivalent)” – tested on Windows 10 only. They work “partially” if the runtime is set to .NET 3.5 – same for .NET 2.0 in Unity 5.6 releases.
In .NET 2.0 and 3.5, there seem to be two problems that cause the editor to crash:
-
Timing – if you try to read from the pipe before the other end has pushed new bytes, the editor will crash. Using the buffer based Read and Write functions, which operate on a whole buffer at once, are really error prone. Rolling your own FOR loops that read and write one byte at a time work much better. I suspect this is a timing issue also-- perhaps the buffer based functions cram data through the pipe too quickly, whereas there is enough overhead in a FOR loop to work around the bug.
-
Pipe directionality – it seems that you can push data across the pipe in only one direction, each time you open/close the pipe. It appears the two ends are not staying in sync on where the write/read pointer is in the stream. For example, I pushed a string across from the client to the server. The server receive the string correctly, and then wrote a response back to the pipe. When the client went to read from the pipe, it died after getting a single byte. That byte, however, happened to have the same value as the first character in the string the client had sent to the server. This is what makes me think that the read/write index is out of sync. As sloopidoopi suggested you have to close the connection after each transmission. I believe this “resets” the pipe. It is a painful solution, though, as both sides would need to maintain state variables which track where they are in your multi-directional protocol.
If you can, and are comfortable with the risk of using the .NET 4.6 experimental runtime, I recommend that as the best solution.
- As a fallback on .NET 2.0 or 3.5, it might be possible to open two pipes and use each as if they are one directional only. One pipe for input to your server, and one for input to your client.