最近在專案中,要求將unity中虛擬相機的座標變化等資訊用socket傳入c++寫的處理程式中。相當於用C#寫使用者端,c++寫伺服器端。主要參考了一下部落格:http://blog.csdn.net/qq_34204419/article/details/82529386
資料型別不對應,編碼方式不一致都可能導致傳輸結果為亂碼。
大佬分別寫了一個C#類和c++結構體進行對齊。
c#:
[Serializable] //序列化物件
[StructLayout(LayoutKind.Sequential, Pack = 1)] // 按1位元組對齊
public class UserMsg
{
public int messageID;
public int clientID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 200)] //限制200位元組
public byte[] message;
}
c++:
typedef struct
{
int messageID;
int clientID;
char message[200];
}UserMsg;
我對大佬程式碼進行了一點改變,符合我的需求。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System;
using System.Runtime.InteropServices;
[Serializable]
[StructLayout(LayoutKind.Sequential,Pack=1)]
public class UserMsg
{
//public int messageID;
//public int clientID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 50)] //限制50位元組
public byte[] message;
}
public class Sockets : MonoBehaviour {
Socket socketsend;
public GameObject cube=null;
// List<byte> list = new List<byte>();
// Use this for initialization\
public static byte[] StructToBytes(object obj)
{
//得到結構體的大小
int size = Marshal.SizeOf(obj);
//建立byte陣列
byte[] bytes = new byte[size];
//分配結構體大小的記憶體空間
IntPtr structPtr = Marshal.AllocHGlobal(size);
//將結構體拷到分配好的記憶體空間
Marshal.StructureToPtr(obj, structPtr, false);
//從記憶體空間拷到byte陣列
Marshal.Copy(structPtr, bytes, 0, size);
//釋放記憶體空間
Marshal.FreeHGlobal(structPtr);
//返回byte陣列
return bytes;
}
void Start ()
{
try
{
socketsend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint point = new IPEndPoint(ip, 50000);
socketsend.Connect(point);
Debug.Log("連線成功!");
//開啟執行緒接收訊息
Thread th = new Thread(Recieve);
th.IsBackground = true;
th.Start();
}
catch
{
Debug.Log("初始化錯誤");
}
}
private void OnGUI()
{
if (GUILayout.Button("結束"))
{
socketsend.Close();
}
}
// Update is called once per frame
void Update ()
{
try
{
if (socketsend.Connected)
{
string strCube_x = cube.transform.position.x.ToString();
string strCube_y = cube.transform.position.y.ToString();
string strCube_z = cube.transform.position.z.ToString();
Debug.Log(strCube_x);
string str_Position = strCube_x + "a" + strCube_y + "b" + strCube_z;
//Debug.Log("12"+str_Position);
UserMsg ux = new UserMsg();
ux.message = Encoding.ASCII.GetBytes(str_Position);
byte[] message_x = StructToBytes(ux);
socketsend.Send(message_x);
}
else
{
Debug.Log("傳送結束!");
}
}
catch(SocketException se)
{
Debug.Log("傳送失敗!");
}
}
//
void Recieve()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 1024 * 3];
int r = socketsend.Receive(buffer);
if (r == 0)
{
break;
Environment.Exit(0);//結束當前程序
}
string str = Encoding.UTF8.GetString(buffer, 0, r);
Debug.Log("receive:" + str);
}
catch { }
}
}
}
#include <WinSock2.h>
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <thread>
#pragma comment(lib,"WS2_32.lib")
using namespace std;
//全域性常數
const int BUF_SIZE = 50;
int flag = 1;
int flag1 = 1;
char inputC = 0;
char str1[] = "a";
char str2[] = "b";
//全域性變數
SOCKET sockSer, sockCli;
SOCKADDR_IN addrSer, addrCli;
int naddr = sizeof(SOCKADDR_IN);
int retValx;
double cube_x ;
double cube_y ;
double cube_z ;
int w ;
int e ;
int tx ,ty;
char sendbuf[BUF_SIZE];
char inputbuf[BUF_SIZE];
//函數宣告
typedef struct
{
char message[50];
}UserMsg;
void posReceive()
{
while (true) {
//ZeroMemory(recebuf, BUF_SIZE);
char recebuf_x[BUF_SIZE];
UserMsg u_x;
retValx= recv(sockCli, recebuf_x, BUF_SIZE, 0);
// cout << retValx << endl;
if (retValx<=0)
{
cout << " recv failed" << endl;
break;
}
u_x = *(UserMsg*)recebuf_x;
w = 0;
e = 0;
tx= 0;
ty= 0;
for (int i = 0; i < retValx; i++)
{
if (u_x.message[i] == str1[0] )
{
char message_x[50];
tx = i;
for (int j = 0; j < tx; j++)
{
message_x[j] = u_x.message[j];
}
cube_x = strtod(message_x, NULL);
}
if (u_x.message[i] == str2[0] )
{
ty = i;
char message_y[50];
char message_z[50];
for (int j = tx+1; j < ty; j++)
{
message_y[w] = u_x.message[j];
w++;
}
cube_y = strtod(message_y, NULL);
for (int j = ty+1; j < retValx; j++)
{
message_z[e] = u_x.message[j];
e++;
}
cube_z = strtod(message_z, NULL);
break;
}
}
cout << cube_x << ","<<cube_y<<","<<cube_z<<endl;
}
}
int main()
{
WSADATA wsdata;
if (WSAStartup(MAKEWORD(2, 2), &wsdata) != 0)
{
//輸出出錯資訊
cout << "載入socket庫出錯!" << endl;
system("pause");
}
//建立Socket
sockSer = socket(AF_INET, SOCK_STREAM, 0);
//初始化地址
addrSer.sin_port = htons(50000);
addrSer.sin_family = AF_INET;
addrSer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
//繫結Socket
bind(sockSer, (SOCKADDR*)&addrSer, sizeof(SOCKADDR));
cout << "bind success!" << endl;
while (flag)
{
//監聽
listen(sockSer, 2);
//接受連線請求
sockCli=accept(sockSer,(SOCKADDR*)&addrCli,&naddr);
if (sockCli != INVALID_SOCKET) {
cout << "連線成功!" << endl;
strcpy_s(sendbuf, "hello!");
send(sockCli,sendbuf,sizeof(sendbuf),0);
thread t1(posReceive);
t1.join();
flag = 0;
}
}
while (flag1)
{
if (inputC == 27)
{
closesocket(sockSer);
closesocket(sockCli);
WSACleanup();
flag1 = 0;
}
}
return 0;
}
將相機的每一幀的位置進行傳送:
string strCube_x = cube.transform.position.x.ToString();
string strCube_y = cube.transform.position.y.ToString();
string strCube_z = cube.transform.position.z.ToString();
主要為x,y,z的座標。將他們變為一個str型別進行傳送。因為主要為數位,在xyzz座標中加入字母進行區分。在伺服器端在進行遍歷,分解。
歡迎大佬批評指正。