Unity與C++之間進行socket通信


 

在本例中我們將以C#作為Unity腳本為例與C++進行通信,所以實質上是C#C++之間進行socket通信。C#C++都提供了socket類,這樣就使得這兩種語言之間可以相互發送並接受消息。從而能夠實現UnityC++之間進行通信,也就使得在C++程序中對Unity程序進行控制成為可能。在本例中我們通過在C++程序中控制實現UnityCube對象的旋轉以及移動操作來說明UnityC++之間進行socket通信。

首先,我們以Unity程序作為客戶端程序,它主要是接收C++客服端發送過來的控制信息,對接收到的消息進行處理然后反應到相應對象實體上(Cube對象)

其次是客服端,客戶端用VC++ 6.0來設計界面,主要用來向Unity服務器端發送控制信息進而控制下UnityCube對象的旋轉和移動。

具體的實現如下:

 

服務器端:首先編寫一個腳本類專門處理socket通信,在這里命名為ServerSocket,其主要實現了以下操作--------建立服務器端socket、啟動線程等待客服端連接、接收消息、向客戶端發送消息、斷開連接。然后編寫另外一個腳本用於對接收到的消息進行相應處理,本例中命名為Test。腳本具體實現如下:

 ServerSocket.cs具體實現代碼:

ServerSocket.cs
using System.Collections;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.IO;
 
public class ServerSocket
{
 
    Socket severSocket;//服務器端Socket
    Socket clientSocket;//客戶端
    Thread thread1;//連接線程
    IPEndPoint clientip;//被連接的ip地址
    string returnStr;//用於傳遞消息的字符串
    string receiveStr;//接收客戶端發來的字符串
    string sendStr;//發送的字符串
 
    int recv;//用於表示客戶端發送的信息長度
    byte[] receiveData = new byte[1024];//用於緩存客戶端所發送的信息,通過socket傳遞的信息必須為字節數組
    byte[] sendData = new byte[1024];//用於緩存客戶端所發送的信息,通過socket傳遞的信息必須為字節數組
 
 
    //程序初始化
    public void Init()
    {
        //初始化命令字符串
        returnStr = null;
        receiveStr = null;
 
        //獲取ip
        string hostName = System.Net.Dns.GetHostName();
        System.Net.IPHostEntry ipEntry = System.Net.Dns.GetHostEntry(hostName);        
//ip地址列表
        System.Net.IPAddress[] addr = ipEntry.AddressList;
 
        //建立服務器端socket
        IPEndPoint ipep = new IPEndPoint(addr[0], 8000);//本機預使用的IP和端口
        severSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        severSocket.Bind(ipep);//綁定
        severSocket.Listen(10);//監聽
        //建立服務器端socket end
 
        //新建線程
        thread = new Thread(new ThreadStart(GoClient));
       //啟動線程
        thread.Start();
    }
 
    void GoClient()
    {
        //客戶端連接
        ConnetClient();
        //用死循環來不斷的從客戶端獲取信息
        while (true)
        {
                      //每次接收數據之前先清空字符數組
            receiveData = new byte[1024];
            recv = clientSocket.Receive(receiveData);
            //當信息長度為0,說明客戶端連接斷開
            if (recv == 0)
            {
                //等待客戶端重新連接
                ConnetClient();
                //進入下一次循環
                continue;
            }
            //接收到的消息
            receiveStr = Encoding.ASCII.GetString(receiveData, 0, recv);
        }
    }
 
    //等待客戶端連接
    void ConnetClient()
    {
        if (clientSocket != null)
        {
            clientSocket.Close();
        }
        //等待連接
//當有可用的客戶端連接嘗試時執行,並返回一個新的socket,用於與客戶端之間的通信
        clientSocket = severSocket.Accept();
    }
 
    //向客戶端發送信息
    public void SendClient(string str)
    {
            sendData = new byte[1024];
            sendData = Encoding.ASCII.GetBytes(str);
            clientSocket.Send(sendData, sendData.Length, SocketFlags.None);  
    }
 
    //返回傳送命令
    public string ReturnStr()
    {
        lock (this)
        {
            returnStr = receiveStr;
        }
        return returnStr;
    }
    //退出整個socket
    public void SocketQuit()
    {
        //先關閉客戶端
        if (clientSocket != null)
        {
            clientSocket.Close();
        }
        //再關閉線程
        if (thread1!= null)
        {
            thread.Interrupt();
            thread.Abort();
        }
        //最后關閉服務端socket
        severSocket.Close();
    }
}

 

Test.cs具體實現代碼:

 

Test.cs
using UnityEngine;
using System.Collections;
public class Test : MonoBehaviour {
    ServerSocket ssock;
    string str=null;
    GameObject obj;
    //旋轉速度
    int rspeed = 100;
    //移動速度
    float mspeed = 0.1f;
         void Start () {
        //初始化ssocket
        ssock = new ServerSocket();
        ssock.Init();
        obj = GameObject.Find("Cube");
         }
    void OnGUI()
    {
           
            //接收消息並處理
            if (ssock.ReturnStr() != null)
            {
                str = ssock.ReturnStr();
                if("RXR"==str )
                {
                    obj.transform.Rotate(Vector3.right * Time.deltaTime * rspeed);
                }
                if ("RXL" == str)
                {
                    obj.transform.Rotate(-Vector3.right * Time.deltaTime * rspeed);
 
                }
                if ("RYR" == str )
                {
                    obj.transform.Rotate(Vector3.up * Time.deltaTime * rspeed);
                }
                if ("RYL" == str)
                {
                    obj.transform.Rotate(-Vector3.up * Time.deltaTime * rspeed);
                }
                if ("RZR" == str )
                {
                    obj.transform.Rotate(Vector3.forward * Time.deltaTime * rspeed);
                }
                if ("RZL" == str)
                {
                    obj.transform.Rotate(-Vector3.forward * Time.deltaTime * rspeed);
                }
                if ("MXR" == str )
                {
                    obj.transform.Translate(Vector3.right * Time.deltaTime * mspeed);
                }
                if ("MXL" == str)
                {
                    obj.transform.Translate(-Vector3.right * Time.deltaTime * mspeed);
                }
                if ("MYR" == str )
                {
                    obj.transform.Translate(Vector3.up * Time.deltaTime * mspeed);
                }
                if ("MYL" == str)
                {
                    obj.transform.Translate(-Vector3.up * Time.deltaTime * mspeed);
                }
                if ("MZR" == str )
                {
                    obj.transform.Translate(Vector3.forward * Time.deltaTime * mspeed);
                }
                if ("MZL" == str)
                {
                    obj.transform.Translate(-Vector3.forward * Time.deltaTime * mspeed);
                } 
            }
            //想客戶端發送消息
            ssock.SendClient("hello1");
        //GUI.Label(new Rect(Screen.width / 2 - 100, Screen.height / 2 - 100, 200, 200), str);
    }
    //當場景退出時
    void OnApplicationQuit()
    {
        //關閉連接
        ssock.SocketQuit();
    }
}

 

  

客戶端:客服端主要實現向服務器端發送數據,以控制Cube對象的旋轉和移動,首先設計好客戶端界面,接着就進行相應發送數據的一些准備工作,比如加載套接字、建立與客戶端的連接等,最后是發送數據的邏輯處理。具體實現如下

1,  打開VC++ 6.0,新建一個MFC AppWizard(exe)工程CppConnectToUnity,選擇創建應用程序的類型為基於對話框(Dialog based),然后打開資源視圖(ResourceView),選擇該工程的應用對話框進行界面設計,其大致界面如下:


2,  選擇類視圖(ClassView),在CCppConnectToUnityApp類中的InitInstance()方法中加載套接字,代碼如下:

//加載套接字庫

if (!AfxSocketInit())

{

  AfxMessageBox("加載套接字失敗!");

  return FALSE;

}

 

3,  選擇類CCppConnectToUnityDlg,給其添加一個私有成員變量

 

 

 

private:

           //套接字描述符變量

         SOCKET  m_socket;

//然后,在OnInitDialog()方法中初始化m_socket變量


//(以下代碼需添加,原作者漏了說明)

WSADATA wsaData; 

::WSAStartup(MAKEWORD(2,2),&wsaData); 

 

//初始化套接字

m_socket=socket(AF_INET,SOCK_STREAM,0);

if (INVALID_SOCKET==m_socket)

{

           MessageBox("套接字創建失敗!");

           return FALSE;

}

 

 

給連接按鈕添加單擊響應方法(雙擊“連接”按鈕即可),在其方法中實現與服務器端的連接

void CCppConnectToUnityDlg::OnBtnConnect()

{

// TODO: Add your control notification handler code here

DWORD dwIP;

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS))->GetAddress(dwIP);

SOCKADDR_IN addrTo;

addrTo.sin_family=AF_INET;

addrTo.sin_port=htons(8000);

addrTo.sin_addr.S_un.S_addr=htonl(u_long(dwIP));

int iResult = connect( m_socket, (SOCKADDR*) &addrTo, sizeof(addrTo) ) ;

if (iResult == SOCKET_ERROR)

{

           MessageBox("連接服務器不成功!");

           //WSACleanup();

           //continue;

}else

{

           MessageBox("連接服務器成功!");

}

}

 

 

給相應的旋轉和移動按鈕添加單擊事件響應方法(雙擊按鈕),然后在編寫代碼:

void CCppConnectToUnityDlg::OnBtnRotXr()

{

// 發送沿x軸正向旋轉的消息

send( m_socket, "RXR", strlen("RXR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnRotXl()

{

//發送沿x軸反向旋轉的消息

send( m_socket, "RXL", strlen("RXL"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnRotYr()

{

//發送沿y軸正向旋轉的消息

send( m_socket, "RYR", strlen("RYR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnRotYl()

{

//發送沿y軸反向旋轉的消息

send( m_socket, "RYL", strlen("RYL"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnRotZr()

{

//發送沿z軸正向旋轉的消息

send( m_socket, "RZR", strlen("RZR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnRotZl()

{

           //發送沿z軸反向旋轉的消息

send( m_socket, "RZL", strlen("RZL"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovXr()

{

//發送沿x軸正向移動的消息

send( m_socket, "MXR", strlen("MXR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovXl()

{

//發送沿x軸反向移動的消息

send( m_socket, "MXL", strlen("MXL"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovYr()

{

//發送沿y軸正向移動的消息

send( m_socket, "MYR", strlen("MYR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovYl()

{

//發送沿y軸反向移動的消息

send( m_socket, "MYL", strlen("MYL"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovZr()

{

//發送沿z軸正向移動的消息

send( m_socket, "MZR", strlen("MZR"), 0 );

}

 

void CCppConnectToUnityDlg::OnBtnMovZl()

{

//發送沿z軸反向移動的消息

send( m_socket, "MZL", strlen("MZL"), 0 );

}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM