在没有 System.Net.Sockets 的情况下将 Unity 连接到 C++ WinSocket

Posted

技术标签:

【中文标题】在没有 System.Net.Sockets 的情况下将 Unity 连接到 C++ WinSocket【英文标题】:Connect Unity to C++ WinSocket WITHOUT System.Net.Sockets 【发布时间】:2017-03-22 20:18:00 【问题描述】:

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 上使用线程也很困难,异步任务似乎也是一个困难的提议。

【问题讨论】:

套接字的文档说它应该可用: System.Net.Sockets 绝对不适用于 Windows 10 通用应用程序。我会很好奇你在哪里看到的。 The official documentation 一件事。 Plus File -> New Project -> Windows 10 Universal 有System.Net.Sockets 可用。也许 Unity 限制了您可以调用的 API? 我相信这是因为 Unity 仅在 .Net 3.5 框架上。据我所知,这不允许在 Windows 10 上使用 System.Net.Sockets。 【参考方案1】:

我们使用 Threads 和 https://github.com/nickgravelyn/UnityToolbag/tree/master/Dispatcher 构建了一个 C++ 到 Unity UDP 客户端,以使其“线程安全”。

根据https://forums.hololens.com/discussion/578/hololens-udp-server,您可以使用 Windows.Networking.Sockets

【讨论】:

你能提供一个完整的例子吗? 我只是回答了您对线程的担忧以及在forums.hololens.com/discussion/578/hololens-udp-server 上找到的解决方案我应该说使用 System.Net.Sockets.UdpPClient。我没有 Hololens :-/forums.hololens.com/discussion/578/hololens-udp-server 中的示例看起来与我的代码非常相似。我不确定我的代码是否是正确的答案。是吗?【参考方案2】:

经过多次尝试和错误,我终于成功了一半。如果有人可以填写此答案中的空白(见下文),我很乐意将接受更改为他们的答案。

简而言之,我确实只使用了 UWP TCP 套接字。构建有点痛苦,它在模拟器上不起作用。切换到硬件而不是模拟器使一切正常。

使用 UWP for Hololens 构建的必要 TCP C# 侦听器:

#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 进行通信,因此我认为在本地计算机上运行时环回不应该是一个问题 - 特别是因为模拟器的 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++ 部分,请使用标准网络套接字。例如,您可以查看Beginner's Socket Programming in C

【讨论】:

这对 Unity 网络有好处,但请检查原始问题:我正在寻找从非统一 C++ 应用程序到统一应用程序的通信。这没有回答我要问的问题。 @user650261 对于从 C++/C 进行连接,请使用标准 TCP 或 UDP 套接字 - 它们与我的回答中描述的 Unity 网络完全兼容。 我已经参考 C++ 中的 Programming sockets 更新了我的答案。 您必须在 C++ 端提供一个工作示例,因为我没有看到它们工作,也没有让它们在我的实验中工作。我也不认为它们会起作用 - LLAPI 与 UDP 或 TCP 不同。 注意:在我的回答中,LLAPI 是比传输层更高级别的协议,它不依赖于 LLAPI。反之亦然 LLAPI 基于此传输层。

以上是关于在没有 System.Net.Sockets 的情况下将 Unity 连接到 C++ WinSocket的主要内容,如果未能解决你的问题,请参考以下文章

System.Net.Sockets.SocketException

System.Net.Sockets.SocketException (10060):连接尝试失败,因为连接方在一段时间后没有正确响应

.NET SSH 隧道 - “System.Net.Sockets.Socket”类型的对象无法转换为“System.Net.Sockets.TcpListener”类型的对象

关闭 NamedPipeClientStream 时出现 System.Net.Sockets.SocketException

System.Net.Sockets.SocketException:'现有连接被远程主机强行关闭'

紧急求助,在传输数据时页面提示无法连接到远程服务器 System.Net.Sockets.SocketException