将Unity与C++ WinSocket连接,无需使用System.Net.Sockets

12

Windows 10,Unity 5.5.2 - 注意这会隐式限制 .Net 版本为 3.5。

我有一个 C++ 应用程序,想要通过无线连接与 Unity 应用程序连接。我希望持续地从 C++ 向 Unity 发送字节数组。但问题在于,对于我想要部署到的设备(我的情况下是 Hololens),System.Net.Sockets 不可用。

在 C++ 中,我使用 Winsock2.h 头文件实例化套接字。我可以使用 UDP 或 TCP,对我的应用程序来说没有关系。

在 Unity 中,我希望使用 Unity.Networking 或 UWP 来建立连接。

使用 UWP,我只看到了使用 async 关键字的示例,这在 Unity 中很麻烦(而且我真的不确定是否可能)。

同时,Unity.Networking 似乎使用自己的协议,我不知道如何将其与我的 C++ 应用程序接口起来。

有人能提供一种非常简单、简洁的方式来在 Unity 中完成这项任务吗?

编辑:在 Hololens 上使用线程也很困难,async 任务似乎也很困难。


套接字的文档说它应该可用: - Peter Torr - MSFT
System.Net.Sockets 绝对不能用于 Windows 10 通用应用程序。我很好奇您在哪里看到的信息。 - user650261
一件事是官方文档。此外,文件 -> 新建项目 -> Windows 10通用平台有System.Net.Sockets可用。也许Unity限制了您可以调用的API? - Peter Torr - MSFT
我认为这是因为Unity仅支持.Net 3.5框架。据我所知,这不允许在Windows 10上使用System.Net.Sockets。 - user650261
3个回答

2

你能提供一个完整的例子吗? - user650261
我只是回答了你关于线程和在https://forums.hololens.com/discussion/578/hololens-udp-server找到的解决方案的担忧。我应该说使用System.Net.Sockets.UdpPClient。我没有Hololens :-/ https://forums.hololens.com/discussion/578/hololens-udp-server中的示例看起来与我的代码非常相似。但我不确定我的代码是否是一个合适的答案。它是吗? - Clemens Tolboom

2

经过多次试验,我终于让它半路工作了。如果有人能填写下面答案中的空白部分,我会很乐意将答案改为他们的答案。

简而言之,我最终只使用了UWP TCP套接字。构建过程有点麻烦,而且在模拟器上无法运行。从模拟器切换到硬件使事情变得可行。

用于Hololens的必要的TCP C#监听器,与UWP一起构建:

#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的情况下从Unity构建,然后在禁用uwp_build的情况下部署到Hololens上,但我不确定原因。在设备本身上,这个过程非常流畅,但是在模拟器上却无法正常工作。随着虚拟机可能会在大约一周后发布Creators 10时被废弃,这可能已经不再重要了,也许新的模拟器可以解决这个问题。由于我在非UWP与UWP之间进行通信,因此在运行本地计算机时不应该存在环回问题——特别是由于模拟器具有不同的IP地址。如果有人知道为什么这在设备上能够成功而在模拟器上不能,并且是否有更方便的构建标志序列,请告诉我,我将不胜感激。

1

有一个传输层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++部分,请使用标准的网络套接字。您可以查看C语言初学者的套接字编程以获取示例。


这对Unity网络通信很有用,但请检查原始问题:我正在寻找一种从非Unity C++应用程序到Unity应用程序的通信方式。这并没有回答我所问的问题。 - user650261
@user650261 如果要从C++/C连接,请使用标准的TCP或UDP套接字 - 它们与我在答案中描述的Unity网络完全兼容。 - Alexander Ushakov
我已经更新了我的答案,并提到了在C中编程套接字,这在C++中是相同的。 - Alexander Ushakov
你需要在C++端提供一个可工作的示例,因为我没有看到它们工作过,也没有在我的实验中让它们工作。我认为它们不会起作用 - LLAPI与UDP或TCP不同。 - user650261
2
注意:在我的回答中,LLAPI是比传输层更高级的协议,它不依赖于传输层。反之,LLAPI基于这个传输层。 - Alexander Ushakov
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接