Подключить Unity к С++ WinSocket БЕЗ System.Net.Sockets

Windows 10, Unity 5.5.2 - обратите внимание, что это неявно ограничивает .Net до версии 3.5.

У меня есть приложение на С++, которое я пытаюсь подключить к приложению Unity по воздуху. Я хочу постоянно отправлять байтовые массивы из С++ в Unity. Уловка заключается в том, что для устройства (Hololens, в моем случае), которое я хочу развернуть, System.Net.Sockets недоступно.

В С++ я создаю экземпляр сокета, используя заголовок Winsock2.h. Я могу использовать UDP или TCP, для меня это не имеет значения для моего приложения.

В Unity я хочу использовать Unity.Networking или UWP для установления соединения.

Чтобы использовать UWP, я видел только примеры, которые используют ключевое слово async, которое является головной болью для использования в Unity (и я честно не уверен, если это возможно).

Между тем, Unity.Networking, похоже, использует свой собственный протокол, и я не уверен, как связать его с моим С++-приложением.

Может ли кто-нибудь предоставить очень простой и сжатый способ выполнения этой задачи в Unity?

РЕДАКТИРОВАТЬ: Использование Threads затруднено и на Hololens, асинхронные задачи также кажутся сложными.

Ответ 1

После долгих проб и ошибок, я, наконец, получил это на полпути. Если кто-то может заполнить пробелы в этом ответе (см. Ниже), я с радостью изменю согласие на их ответ.

Вкратце, я закончил работу только с использованием сокетов UWP TCP. Сборка - это боль, и она не работает на эмуляторе. Переключение на оборудование вместо эмулятора заставило все работать.

Необходимый прослушиватель TCP С#, который пугает с UWP для 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

}

Мне нужно построить из единства с включенным uwp_build, а затем развернуть на Hololens с отключенным - я не уверен, почему.

Во всяком случае, это очень хорошо работает на самом устройстве. Он не работает на эмуляторе. С эмулятором, казалось бы, устаревшим, когда Creators 10 выпускает через неделю или около того, это может быть спорным вопросом - возможно, он будет работать на новом симуляторе. Поскольку я общаюсь с не-UWP в UWP, я не думаю, что loopback должен быть проблемой при работе на локальном компьютере, особенно потому, что у эмулятора есть другой IP-адрес, чем у хост-устройства. Если кто-нибудь знает, почему это будет работать на устройстве, но не на эмуляторе, и если есть более удобная последовательность флагов сборки, я был бы очень благодарен за это.

Ответ 3

Для таких задач существует Transport Layer API. Это код из его образцов:

// 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);

Функция для приема данных:

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;
    }
}

Для части C/С++ используйте стандартные сетевые сокеты. Для примера вы можете проверить Программирование сокета для начинающих в C