How do I get named pipes to work in Unity?

Hello,

I’ve been trying to used named pipes in order to send data from one application to Unity, and I was thinking that named pipes would be a good idea. However, whenever I try creating the Server, I get a win32exception error so that apparently the server is never created. I can create the client, I believe, because I get a NamedPipeClientStream object with no errors, and then when I try using pipe.Connect() I get the same excact win32 error. This is probably because there is no established server to connect to.

My confusion is why I can create the client, but not the server? The syntax for both seems to be the same in its documentation. Here are both the examples I ran, and the reason I am using so many namespaces is because this is part of a larger chunk of code, but maybe the other namespaces are interfering with the pipe declaration.

PipeServerTest.cs:

 using UnityEngine;
    using System.Collections;
    using System;
    using System.IO;
    using System.IO.Pipes;
    using System.Text;
    using System.Threading;
    using System.ComponentModel;
    
    public class PipeServerTest : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
    		try{
    			NamedPipeServerStream pipeServer = new NamedPipeServerStream("testpipe"){
    			print (pipeServer);
    		}
    		catch(Win32Exception w){
    			print(w.Message);
    			print(w.ErrorCode.ToString());
    			print(w.NativeErrorCode.ToString());
    			print(w.StackTrace);
    			print(w.Source);
    			Exception e=w.GetBaseException();
    			print(e.Message);
    		}
    	}
    }

PipeClientTest.cs:

using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Security.Principal;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;

public class PipeClientTest : MonoBehaviour {

	// Use this for initialization
	void Start(){
		NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut);
		print (pipeClient);
		try{
		pipeClient.Connect();
		}
		catch(Win32Exception w){
			print(w.Message);
			print(w.ErrorCode.ToString());
			print(w.NativeErrorCode.ToString());
			print(w.StackTrace);
			print(w.Source);
			Exception e=w.GetBaseException();
			print(e.Message);
		}
	}
}

I’d also like to note that I’m not sure if this should go in a Start() function. When I use Main() I get no outputs… or maybe that’s intended.

Reference to named Pipes

It might be that Unity is limited in what it allows for inter-process communication. Maybe try putting all the pipe code in a dll as this person suggested?

http://forum.unity3d.com/threads/23472-Pipe-between-Unity-and-external-app-%28C-Windows%29

Then you’d use DLL Import calls via a C# wrapper class in Unity to call the appropriate methods from the DLL.

http://docs.unity3d.com/Documentation/Manual/Plugins.html

Also Start is automtically called before the first Update in Unity. Main is not used. Awake occurs before all Starts. Here’s a link to more details on Execution Order in Unity.

http://docs.unity3d.com/Documentation/Manual/ExecutionOrder.html

Sorry not a perfect answer, as I’ve never done or seen pipe communication in Unity. But I hope this helps!

To get a pipe between Unity3D app and Windows application I used UDPClient. P2P worked fine for me.

I see a possible sources of problem: The pipe you are trying to create (in the constructor call of the server’s pipe end) already exists in the operating system. I think the letter case of the pipe name is not differentiated.

This could answer the fact that you can create the client, as it just searches in the operating system for the pipe with given name.

using UnityEngine;
using System.Collections;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Text;
using System;
using System.Security.Principal;
using System.Diagnostics;

public class PipeDataReceive : MonoBehaviour {

    public NamedPipeClientStream pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.Asynchronous);
    public StreamString ss;
    Thread readThread;

    // Use this for initialization
    void Start () {

        UnityEngine.Debug.Log("Pipe Opening Process Started");

        UnityEngine.Debug.Log("Connecting to server...

");
pipeClient.Connect();
StreamString ss = new StreamString(pipeClient);

        UnityEngine.Debug.Log(ss.ReadString());


        Thread.Sleep(250);
    }
	
	// Update is called once per frame
	void Update () {

        UnityEngine.Debug.Log("Updating");

      
       getPipedData()

    }

    private void getPipedData()
    {
        //UnityEngine.Debug.Log("Thread Called - Start");

        StreamString ss = new StreamString(pipeClient);
        UnityEngine.Debug.Log(ss.ReadString());
        //UnityEngine.Debug.Log("Thread Called - End");

    }
}



public class StreamString
{
    private Stream ioStream;
    private UnicodeEncoding streamEncoding;

    public StreamString(Stream ioStream)
    {
        this.ioStream = ioStream;
        streamEncoding = new UnicodeEncoding();
    }

    public string ReadString()
    {
        int len;
        len = ioStream.ReadByte() * 256;
        len += ioStream.ReadByte();
        byte[] inBuffer = new byte[len];
        ioStream.Read(inBuffer, 0, len);

        string outString = streamEncoding.GetString(inBuffer);

        //ioStream.Flush();

        return outString;


    }

    public int WriteString(string outString)
    {
        byte[] outBuffer = streamEncoding.GetBytes(outString);
        int len = outBuffer.Length;
        if (len > UInt16.MaxValue)
        {
            len = (int)UInt16.MaxValue;
        }
        ioStream.WriteByte((byte)(len / 256));
        ioStream.WriteByte((byte)(len & 255));
        ioStream.Write(outBuffer, 0, len);
        ioStream.Flush();

        return outBuffer.Length + 2;
    }




}

It Took me forever to get pipes working with my project… One of the keys is to change your project to use the full .NET 2 library instead of the .NET 2 subset. You can do this in by going to (Edit->Project Settings → Player) then under the ‘Other Settings’ dropdown menu, selecting ‘.NET 2.0’ instead of ‘.NET 2.0 Subset’ in the ‘Api Compatibility Level’ box.

82320-unity2subnet.png

On the other end, check out this reference for the server side process…

You’ve just got to add a while loop to your primary pipe thread that keeps sending data into Unity.

There’s probably some things I’ve overlooked, as far as properly shutting down the threads and connections and such, but finally got my programs talking after about 20 hours (literally) of hair-pulling. Figured I’d record the process to save some hair-pulling for the rest of ya.

Pretty proud, I’ve got my $30 used first-generation kinect to stream in IR data and follow IR points. Would have been easier to drop the $300 on the kinect 2.0 and upgrade to windows 8 or 10, but I’ve got all I need now :slight_smile:

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 are two problems though 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. Other people have 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.