如何同时通过UDP和两端的后处理数据报连续发送和接收(使用同一套接字?)

时间:2019-04-17 09:47:29

标签: c# c++ unity3d udp

这是一个问题,主要是由于我对Winsock,套接字,UDP和一般的编程经验不足。与该问题相关的问题/答案很多,但由于对Winsock等的理解不足,我无法对其进行筛选,以了解如何解决我的问题。

问题。 我目前通过C ++应用程序和在Unity应用程序中运行的C#脚本正确地(连续)运行UDP连接。当前,C ++应用程序将来自外部触觉设备的位置数据信息转换为简单的字符串,然后通过UDP将数据报发送到unity应用程序。然后,Unity脚本将简单字符串转换回相关信息,并用于控制Unity游戏空间内的对象。这可以正常工作,但是主要是因为我已经能够在线找到脚本,只需要进行少量编辑和调整即可针对我的特定应用程序工作。我现在需要做的是将数据报从Unity应用程序发送到C ++应用程序(与我目前正在执行的操作相反),以便当游戏对象与Unity游戏空间中的对撞机进行交互时向触觉设备提供触觉反馈。当与对撞机建立联系时,我有想要发送的数据(当前通过Debug.Log打印),但是我不知道如何正确使用winsock Sentto和Recvfrom函数来使C ++应用程序主动监听(不只是发送),而且Unity应用程序正在主动发送(不只是侦听)。

我将继续浏览已经发布的问题/解决方案,看看是否可以解决,但与此同时,如果有人可以提供一些帮助,我将不胜感激。我正在使用的代码的相关部分发布在下面:

此脚本已附加到Unity中我的游戏对象上

using UnityEngine;
using System.Collections;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Globalization;
using UnityEngine.Serialization;

public class TestUDPConnection : MonoBehaviour
{

    private const int listenPort = 11000;
    private UdpClient listener;
    private IPEndPoint remoteIpEndPoint;

    public static string currentUDPData;
    private Thread listenerThread;
    public bool inputSignal = false;

    //bool to fix unity crash
    public int fixMe = 1;

    // Use this for initialization
    void Start ()
    {
        // Creat a new thread for receiving UDP messages
        listenerThread = new Thread(new ThreadStart(UDPReceive));
        listenerThread.Name = "UDP Receiving Thread";
        listenerThread.IsBackground = true; // run thread in background
        listenerThread.Start();
    }

    // Thread for receiving UDP input
    public void UDPReceive()
    {
        Debug.Log("Start receiving UDP.");

        listener = new UdpClient(listenPort); // Initializes and BINDS directly (this is an overload of the UdpClient function, or to be precise the Constructor)
        while (fixMe > 0) {
            try {
                // Opening udpclient listener on port
                Debug.Log("Listening to port: " + listenPort);

                // Receive bytes
                remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // Initializes the Endpoint with the correct Port and any IP address (UDP is connectionless the receiver doesn't need any IP address)
                byte[] receiveBytes = listener.Receive(ref remoteIpEndPoint);

                // Encode bytes to string (with UTF8 or ASCII Encoding)
                currentUDPData = Encoding.ASCII.GetString(receiveBytes);

                try {
//code is parsed here

                } catch (Exception parseError) {
                    Debug.Log("Parsing didn't work: " + parseError.ToString());
                }
            } catch (Exception e) {
                Debug.Log("Something went wrong: " + e.ToString());
            }
        }

        Debug.Log("Stop receiving UDP.");

    }
    // Update is called once per frame
    void Update ()
    {
        // Executed when BACKSPACE key hit
            if (Input.GetKeyDown("backspace")) {
                DestroyObject(gameObject);
                fixMe = 0;
    }
}
    // Executed when object gets destroyed
    void OnDisable()
    {
        if (listenerThread != null) {
            listenerThread.Abort();
        }
        listener.Close();
        Debug.Log("UDP receiver closed");
        fixMe = 0;
    }
} 

这是我在C ++应用程序中拥有的脚本(脚本中有更多与触觉设备有关的代码,但这部分与UDP通信有关)

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>
#include <vector>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int iResult;
WSADATA wsaData;

SOCKET SendSocket = INVALID_SOCKET;
sockaddr_in RecvAddr;

unsigned short Port = 11000; //port communicated through

char SendBuf[1024]; //message variable
int BufLen = 1024; //max length of buffer

int main()
{
// Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup failed with error: %d\n", iResult);
        //return 1;
    }

    //---------------------------------------------
    // Create a socket for sending data
    SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (SendSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        //return 1;
    }
    //---------------------------------------------
    // Set up the RecvAddr structure with the IP address of
    // the receiver (in this example case "192.168.1.1")
    // and the specified port number.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    //InetPton(AF_INET, _T("127.0.0.1"), &RecvAddr.sin_addr.s_addr);

    //---------------------------------------------
    // Clean up and quit.
    //wprintf(L"Exiting.\n");
    //WSACleanup();
    //return 0;

//the udp communication, data parsing, etc., is contained within this loop:
// main haptic simulation loop
    while (simulationRunning)
{
//script here for various stuff...
//taking in position values of haptic device in different variables
//converting them to strings
//adding them to the pBuffer that is sent through the UDP pipeline via:

iResult = sendto(SendSocket,
                    pBuffer, nStrSize + 1, 0, (SOCKADDR *)& RecvAddr, sizeof(RecvAddr));
                if (iResult == SOCKET_ERROR) {
                    wprintf(L"sendto failed with error: %d\n", WSAGetLastError());
                    closesocket(SendSocket);
                    WSACleanup();
                    //return 1;
                }
    }

因此,基本上,我想实现每个代码中发生的事情的相反过程(即,在C#Unity脚本中发送数据并在C ++应用程序脚本中接收数据)。根据我的阅读,您可以在同一套接字上发送/接收,因此似乎很容易在我的C ++仿真循环中添加几行,其中包括recvfrom函数,以及我的c ++循环的一些简单复制和粘贴。进入C#脚本(只需进行少量调整)即可获取发送的数据。我将阅读更多内容,并尝试使用不同的代码以使其同时起作用。提前感谢您提供的任何帮助!

0 个答案:

没有答案