12

Windows 10, Unity 5.5.2 - note that this implicitly restricts .Net to version 3.5.

I have a C++ application that I'm trying to connect to a Unity application over the air. I wish to continually send byte arrays from C++ to Unity. The catch is that, for the device (Hololens, in my case) that I wish to deploy to, System.Net.Sockets is not available.

In C++ I instantiate a socket using the Winsock2.h header. I can use UDP or TCP, it doesn't matter to me for my application.

In Unity, I wish to use either Unity.Networking or UWP to establish the connection.

To use UWP, I've only seen examples that use the async keyword, which is a headache to use in Unity (and I'm honestly not sure if it's possible).

Meanwhile, Unity.Networking seems to use its own protocol, and I'm not sure how to interface it with my C++ application.

Can anyone provide a very simple, concise way of accomplishing this task in Unity?

EDIT: Using Threads is difficult on the Hololens as well, async tasks seem to be a difficult proposition as well.

user650261
  • 2,115
  • 5
  • 24
  • 47
  • The documentation for sockets says it should be available: – Peter Torr - MSFT Mar 25 '17 at 04:29
  • System.Net.Sockets is definitely not available for Windows 10 Universal apps. I would be curious where you saw otherwise. – user650261 Mar 27 '17 at 18:50
  • [The official documentation](https://msdn.microsoft.com/en-us/library/system.net.sockets.socket(v=vs.110).aspx) for one thing. Plus File -> New Project -> Windows 10 Universal has `System.Net.Sockets` available. Maybe Unity is limiting the APIs you can call? – Peter Torr - MSFT Mar 28 '17 at 01:03
  • I believe it is because Unity is only on the .Net 3.5 framework. As far as I can tell, this does not allow for System.Net.Sockets on Windows 10. – user650261 Mar 28 '17 at 01:29

3 Answers3

2

We have build a C++ to Unity UDP client using Threads and https://github.com/nickgravelyn/UnityToolbag/tree/master/Dispatcher to make it 'Thread safe'.

According to https://forums.hololens.com/discussion/578/hololens-udp-server you could use Windows.Networking.Sockets

Clemens Tolboom
  • 1,872
  • 18
  • 30
  • Can you provide a complete example? – user650261 Mar 31 '17 at 15:23
  • I merely answered regarding your worries about threads and the found solution on https://forums.hololens.com/discussion/578/hololens-udp-server I should have said using System.Net.Sockets.UdpPClient. I have no Hololens :-/ The example in https://forums.hololens.com/discussion/578/hololens-udp-server looks quite similar to my code. I'm not sure my code is a proper answer though. Is it? – Clemens Tolboom Apr 02 '17 at 07:47
2

After much trial and error, I finally got it halfway working. If someone can fill in the blanks in this answer (see below), I will gladly change the accept to their answer.

In short, I did wind up just using UWP TCP sockets. The build is kind of a pain, and it does not work on the emulator. The switch to hardware instead of the emulator made things work.

The necessary TCP C# listener that bulids with UWP for Hololens:

#define uwp
//#define uwp_build

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Text;
using System;
using System.Threading;
using System.Linq;



#if uwp
#if !uwp_build
using Windows.Networking;
using Windows.Networking.Sockets;
using UnityEngine.Networking;
using Windows.Foundation;
#endif
#else
using System.Net;
using System.Net.Sockets;
#endif

public class Renderer : MonoBehavior {

byte[] bytes = new byte[8192];
bool ready = false;
const int localPort = 11000;

static bool clientConnected;

#if !uwp

    TcpListener listener;
    private Socket client = null;

#else
#if !uwp_build

    StreamSocketListener socketListener;
    StreamSocket socket;
#endif
#endif

#if !uwp_build
    async
#endif
    void Start()
    {
        clientConnected = false;

#if !uwp
        IPAddress localAddr = IPAddress.Parse("127.0.0.1");
        listener = new TcpListener(localAddr, localPort);
        listener.Start();
        Debug.Log("Started!");

#else
#if !uwp_build
        socketListener = new StreamSocketListener();


        socketListener.ConnectionReceived += OnConnection;

        await socketListener.BindServiceNameAsync("11000");

}
#endif
#endif

void Update()
    {
#if !uwp
        if (listener.Pending())
        {
            client = listener.AcceptSocket();
            clientConnected = true;
        }
#endif
        // An incoming connection needs to be processed.  
        //don't do anything if the client isn't connected
        if (clientConnected)
        {



            int bytesRec = 0;
#if !uwp
            bytesRec = client.Receive(bytes);
#else
#if !uwp_build
            Stream streamIn = socket.InputStream.AsStreamForRead();

            bytesRec = streamIn.Read(bytes, 0, 8192);
            Debug.Log(bytesRec);
#endif


#endif
            byte[] relevant_bytes = bytes.Take(bytesRec).ToArray();

            //do something with these relevant_bytes

    }
#if uwp
#if !uwp_build
    private async void OnConnection(
        StreamSocketListener sender,
        StreamSocketListenerConnectionReceivedEventArgs args)
    {
        String statusMsg = "Received connection on port: " + args.Socket.Information.LocalPort;
        Debug.Log(statusMsg);
        this.socket = args.Socket;
        clientConnected = true;
    }
#endif
#endif

}

I have to build from unity with uwp_build enabled, and then deploy to the Hololens with it disabled - I'm not sure why.

At any rate, this works pretty seamlessly on the device itself. It doesn't work on the emulator. With the emulator seemingly being deprecated when Creators 10 releases in a week or so, this may be a moot point - maybe it will work on the new simulator. Since I'm communicating from non-UWP to UWP, I don't think loopback should be an issue when running on a local machine - especially since the emulator has a different IP address than the host device. If anyone knows why this would work on the device but not on the emulator and if there's a more convenient build flag sequence, I would be very grateful to know.

user650261
  • 2,115
  • 5
  • 24
  • 47
1

There is a Transport Layer API for such tasks. This is code from its samples:

// Initializing the Transport Layer with no arguments (default settings)
NetworkTransport.Init();

// An example of initializing the Transport Layer with custom settings
GlobalConfig gConfig = new GlobalConfig();
gConfig.MaxPacketSize = 500;
NetworkTransport.Init(gConfig);

ConnectionConfig config = new ConnectionConfig();
// use QosType.Reliable if you need TCP
int myReiliableChannelId  = config.AddChannel(QosType.Reliable);
// use QosType.Unreliable if you need UDP
int myUnreliableChannelId = config.AddChannel(QosType.Unreliable);

HostTopology topology = new HostTopology(config, 10);
// set listen port 8888
int hostId = NetworkTransport.AddHost(topology, 8888);

Function for data receiving:

void Update()
{
    int recHostId; 
    int connectionId; 
    int channelId; 
    byte[] recBuffer = new byte[1024]; 
    int bufferSize = 1024;
    int dataSize;
    byte error;
    NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
    switch (recData)
    {
        case NetworkEventType.Nothing:         //1
            break;
        case NetworkEventType.ConnectEvent:    //2
            break;
        case NetworkEventType.DataEvent:       //3
            break;
        case NetworkEventType.DisconnectEvent: //4
            break;
    }
}

For C/C++ part use standard network sockets. For examples you may check Beginner's Socket Programming in C

Community
  • 1
  • 1
Alexander Ushakov
  • 5,139
  • 3
  • 27
  • 50
  • This is good for Unity networking, but please check the original question: I am looking for communicating from a non-unity C++ app to a unity app. This doesn't answer the question I'm asking. – user650261 Mar 27 '17 at 18:49
  • @user650261 For connecting from C++/C use standart TCP or UDP sockets - they are completely compatible with Unity networking described in my answer. – Alexander Ushakov Mar 27 '17 at 19:08
  • I've updated my answer with reference to the Programming sockets in C which is the same in C++. – Alexander Ushakov Mar 27 '17 at 19:13
  • You would have to provide a working example on the C++ side, as I have not seen them working and nor have I gotten them working in my experimentation. Nor would I think they would work - LLAPI is different from UDP or TCP. – user650261 Mar 27 '17 at 19:13
  • Ok, later I'll give you an example from my projects. Though Unity part isn't on Hololens all works just fine. – Alexander Ushakov Mar 27 '17 at 19:18
  • 2
    Note: LLAPI is a higher level protocol than Transport Layer in my answer which doesn't depend on LLAPI. Vice versa LLAPI is based on this Transport Layer. – Alexander Ushakov Mar 27 '17 at 19:26
  • Okay, well, I tried working with the Transport Layer directly shortly after I asked this, and I got no success. It is not clear to me what protocol Transport Layer uses if not LLAPI. If you can provide an example of working code, I will absolutely try it. – user650261 Mar 27 '17 at 19:59