Unity中c#为客户端,c++为服务器端进行socket通信

Unity中c#为客户端,c++为服务器端进行socket通信

1.需求

最近在项目中,要求将unity中虚拟相机的坐标变化等信息用socket传入c++写的处理程序中。相当于用C#写客户端,c++写服务器端。主要参考了一下博客:http://blog.csdn.net/qq_34204419/article/details/82529386

2.注意C#与C++数据类型的对应关系

在这里插入图片描述数据类型不对应,编码方式不一致都可能导致传输结果为乱码。
大佬分别写了一个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;

3.code

我对大佬代码进行了一点改变,符合我的需求。

Unity,c#,客户端

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 {
    
     }
        }
    }
}

c++,服务器端

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

4. 主要思想

将相机的每一帧的位置进行发送:

                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坐标中加入字母进行区分。在服务端在进行遍历,分解。

5.结果

Unity

在这里插入图片描述在这里插入图片描述

c++端

在这里插入图片描述在这里插入图片描述欢迎大佬批评指正。

猜你喜欢

转载自blog.csdn.net/m0_45866718/article/details/108800439