在本例中我們將以C#作為Unity腳本為例與C++進行通信,所以實質上是C#與C++之間進行socket通信。C#與C++都提供了socket類,這樣就使得這兩種語言之間可以相互發送並接受消息。從而能夠實現Unity與C++之間進行通信,也就使得在C++程序中對Unity程序進行控制成為可能。在本例中我們通過在C++程序中控制實現Unity中Cube對象的旋轉以及移動操作來說明Unity與C++之間進行socket通信。
首先,我們以Unity程序作為客戶端程序,它主要是接收C++客服端發送過來的控制信息,對接收到的消息進行處理然后反應到相應對象實體上(如Cube對象)。
其次是客服端,客戶端用VC++ 6.0來設計界面,主要用來向Unity服務器端發送控制信息進而控制下Unity中Cube對象的旋轉和移動。
具體的實現如下:
服務器端:首先編寫一個腳本類專門處理socket通信,在這里命名為ServerSocket,其主要實現了以下操作--------建立服務器端socket、啟動線程等待客服端連接、接收消息、向客戶端發送消息、斷開連接。然后編寫另外一個腳本用於對接收到的消息進行相應處理,本例中命名為Test。腳本具體實現如下:
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具體實現代碼:

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