Unity C#作为客户端与C++服务器 传递结构体进行Socket通讯

最近接触到C#和C++进行SOCKET通讯的问题。

讲述一下我的情况:

 和我合作的是一个只懂C++的程序员  , 而我是一个经常使用C# 对C++知之甚少的人,  没办法  半路出家。

C++的服务器是他写的     C#的客户端是我写的。  说实话,这个问题困扰了我长达2周之久。  期间我有一种我是中国人而那个人却是个美国人的感觉。

 

下面贴一下思路和代码

C++这边我不是特别会写,在网上找了个简单的代码稍微改了改建立Socket服务器

 

 

 

#include <thread>
#include "winsock2.h"
#include <iostream>


WORD sockVersion = MAKEWORD(2, 2);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	//创建套接字  
	slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (slisten == INVALID_SOCKET)
	{
		printf("socket error !");
		return 0;
	}

	//绑定IP和端口  
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;

	if (_WINSOCK2API_::bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("bind error !");
	}

	//开始监听  
	if (listen(slisten, 5) == SOCKET_ERROR)
	{
		printf("listen error !");
		return 0;
	}

	//循环接收数据  
	thread task01(SendData);

 

SendData函数的方法可以自己写 , 这里开了个线程不听的发送。 方法体主要写自己要发送的内容

//发送数据
void SendData()
{
	while (true)
	{
		printf("等待连接...\n");
		sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
		if (sClient == INVALID_SOCKET)
		{
			printf("accept error !");
			continue;
		}
		printf("接受到一个连接");



		//发送数据  

		send(sClient, (char*)(&cvData), sizeof(OpenCvData), 0);

	}
}

到这里就需要说一下 C++和C# 之间的数据格式需要在网上查一下  我这里发送的是一段Double类型的结构体。如下:

struct OpenCvData
{
	double pos[32];
	double LinePos[4];
}cvData;

好了 C++部分的服务器已经完成了。 

现在是C#部分的客户端接收了,这里不累述。直接贴代码。  讲一下流程

1.建立SOCKET客户端

2.创建和C++对应类型的结构体 并序列化和规定好长度

3.解析接收到的字节,转换成自己需要的结构体

 

第一步的代码如下,初始化的时候就把SOCKET建立好  并开启线程接收。

public ClientSocket(RobotT handler)
    {

        ip = IPAddress.Parse("127.0.0.1");
        port = 8888;
        reciveMsg = handler;
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(ip, port);

        Thread reciveMessageFromServer = new Thread(ReciveMessageFromServer);
        reciveMessageFromServer.Start();
    }

 

 

 

第二步代码如下,这里要重点讲一下,因为我写结构体的时候并没有初始化 ,所以在新建一个对象以后要对他进行初始化

 private void ReciveMessageFromServer()
    {
        while (true)
        {

            if (clientSocket == null)
            {
                Debug.Log("客户端的套接字没了");
                continue;
            }


            Debug.Log("服务器向客户端发送消息成功");
            int bufferCount = clientSocket.Receive(buffer); //阻塞型接收
            // string msg = Encoding.UTF8.GetString(buffer, 0, bufferCount);


            try
            {
                DS = new DataStruct();
                DS.Pos = new double[32];
                DS.LinePos = new double[4];
                DS = (DataStruct)BytesToStruct(buffer, DS.GetType());
                for (int i = 0; i < DS.Pos.Length; i++)
                {
                    Debug.Log(DS.Pos[i]);
                }
                for (int i = 0; i < DS.LinePos.Length; i++)
                {
                    Debug.Log(DS.LinePos[i]);
                }

            }
            catch (Exception)
            {
                Debug.Log("数据异常");
                continue;
            }

        }
    }

 

第三步其实应该是第二步  ,但是为了好给大家呈现解析的代码  就放在这里写了。

下面是和C++对应的结构体,这里需要说明一下   

第一行是序列化这个结构体

第二行是结构体的大小

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 这个是设置序列化的数据的长度

[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DataStruct
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public double[] Pos;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public double[] LinePos;


}

以下是字节转换成结构体的代码,直接复制粘贴就好了 


    public object BytesToStruct(byte[] bytes, Type type)
    {
        int size = Marshal.SizeOf(type);
        IntPtr structPtr = Marshal.AllocHGlobal(size);
        Marshal.Copy(bytes, 0, structPtr, size);
        object obj = Marshal.PtrToStructure(structPtr, type);
        Marshal.FreeHGlobal(structPtr);
        return obj;
    }

全部代码就是这些了,写的比较急可能不是特别详细  。有不明白的可以问我

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值